DynamoDB client for node.js
Switch branches/tags
Nothing to show
Pull request Compare This branch is 84 commits behind jed:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Build Status

This is a node.js binding for the DynamoDB service provided by Amazon Web Services. It currently supports the entire DynamoDB API in an unsugared (read: Amazon-flavored (read: ugly)) format. I'll be developing a more comfortable API over the coming week to make DynamoDB operations more node-ish, so stay tuned.


Abstract DynamoDB's implementation (request signing, session tokens, pagination), but not its tradeoffs/philosophy.


var dynamo = require("dynamo")
  , db = dynamo.createClient()
  , tables = []

db.tables.forEach(function(err, name, next) {
  if (err) return console.warn(err)

  console.log("found a table: " + table.name)

  if (next) next() // use connect-style continuations for batching


  • All callbacks are optional, and if omitted will use console.warn for errors and console.log otherwise. This makes it easier to inspect your database in a REPL, for example.

  • The signature for all callbacks is (err, data, next). This is the same as the standard for most node.js programs, but with an additional next parameter: a continuation function such as those used in Connect routes and other middleware. This function takes no arguments, and is passed only in the following cases:

    • The call was unsuccessful and can be retried. This is the case when DynamoDB returns a 5xx status code, indicating that the problem exists with the service, not the request. Calling next() will execute the same request again, so it's best used with setTimeout.
    • The call was successful and has subsequent results, such as for pagination or when a response hits the 1MB limit. Calling next() will fetch the next batch of results and call back again.

This allows you to write code like this, which logs a list of all tables:

db = dynamo.createClient()
tables = []

db.tables.fetch(function(err, data, next) {
  if (err) {
    if (!next) throw err        // give up (for 4xx errors)
    else setTimeout(next, 5000) // try again in 5s (for 5xx errors)

  else {
    tables.push.apply(tables, data)

    if (!next) console.log(tables) // log it, we've hit the end
    else next()                    // fetch the next batch and call again


dynamo = require("dynamo")

This module exposes the createClient method, which is the preferred way to interact with dynamo. It also provides the core constructors it uses (such as Account, Database, Session, and Table), so that you can override any defaults stored as prototype properties as necessary.


db = dynamo.createClient([credentials])

Returns a database instance attached to the account specified by the given credentials. The credentials can be specified as an object with accessKeyId and secretAccessKey members such as the following:

db = dynamo.createClient({
  accessKeyId: "...",    // your access key id
  secretAccessKey: "..." // your secret access key

You can also omit these credentials by storing them in the environment under which the current process is running, as AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

If neither of the above are provided, an error will be thrown.

db[operationName](data, cb)

All of the original DynamoDB operations are provided as methods on database instances. You won't need to use them unless you want to sacrifice a clean interdace for more control, and don't mind learning Amazon's JSON format.


tables = db.tables

Each client includes a table list object used to interact with DynamoDB tables.


tables.fetch(limit, [cb])

Calls back with the tables in the current database, as a list of table instances. This is subject to pagination depending on the number of results, and the number of items in each batch fetched can be specified with an optional leading limit integer.


A convenience method that uses the fetch method to call back for each table fetched. This abstracts away batching, making it much easier to iterate over tables in a natural yet non-blocking way.


table = new db.Table([options])

Returns a table instance.

recipeTable = new db.Table({
  name: "recipes",
  schema: {userId: Number, date: String},
  throughput: {read: 10, write: 10}

options can be an object with the following properties:

  • name: The name of the table (required)

  • schema: The schema of the table (optional), which can be specified as an object, and needs to have either one or two keys. The first key is required and used as the hash key, and the second is option and used as the range key. The values of these keys can be the global String and Number constructors (or the strings "S" or "N"). All of the following are valid:

{myHashKey: Number}
{myHashKey: "N"}
{myHashKey: Number, myRangeKey: String}
{myHashKey: "N", myRangeKey: "S"}
  • throughput: The throughput of the table (optional), with read and write keys.


Creates a table with the schema and throughput as specified in when the table was instantiated. A schema is required for table creation, but the throughput is optional and defaults to the DynamoDB minimums: 3 ReadCapacityUnits and 5 WriteCapacityUnits.


Fetches details about the table, which can include its status, size, schema, and other details, such as the following. The value returned is a table instance, with properties such as the following:

  CreationDateTime: Fri, 03 Feb 2012 08:09:12 GMT,
  ItemCount: 0,
  KeySchema: {
    HashKeyElement: { AttributeName: 'user', AttributeType: 'S' },
    RangeKeyElement: { AttributeName: 'date', AttributeType: 'N' }
  ProvisionedThroughput: {
    LastIncreaseDateTime: Fri, 03 Feb 2012 08:09:12 GMT,
    ReadCapacityUnits: 3,
    WriteCapacityUnits: 5
  TableName: 'myTable',
  TableSizeBytes: 0,
  TableStatus: 'UPDATING'


Deletes the table.


Polls every 5 seconds until the status of the table changes.

Item, ItemList, etc.

Coming this week!

Low-level API

If you'd like more control over how you interact with DynamoDB, all 12 original DynamoDB operations are available as camelCased methods on database instances return by dynamo.createClient(). These methods are used by the higher-level APIs, and require the object format expected by Amazon.

  • batchGetItem
  • createTable
  • deleteItem
  • deleteTable
  • describeTable
  • getItem
  • listTables
  • putItem
  • query
  • scan
  • updateItem
  • updateTable

These allow you to skip dynamo's API sugar and use only its account, session, and authentication logic, for code such as the following for createTable:

var dynamo = require("dynamo")
  , db = dynamo.createClient()
  , cb = console.log.bind(console)

  TableName: "DYNAMO_TEST_TABLE_1",

  ProvisionedThroughput: {
    ReadCapacityUnits: 5,
    WriteCapacityUnits: 5

  KeySchema: {
    HashKeyElement: {
      AttributeName: "hash",
      AttributeType: "S"
}, cb)


Testing for dynamo is handled using continuous integration against a real DynamoDB instance, under credentials limited to Travis CI.

If you'd like to run the test stuie with your own credentials, make sure they're set using the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, and then run the tests:

npm test

The test suite creates two tables called DYNAMO_TEST_TABLE_1 and DYNAMO_TEST_TABLE_2 before the tests are run, and then deletes them once the tests are done. Note that you will need to delete them manually in the event that the tests fail.



Copyright (c) 2012 Jed Schmidt. See LICENSE.txt for details.

Send any questions or comments here.