DynamoDB client for node.js
Switch branches/tags
Nothing to show
Pull request Compare This branch is 99 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.

tables.add(name, args...)

An alias for tables.get(name).create(args...).

tables.remove(name, args...)

An alias for tables.get(name).destroy(args...).


table = tables.get(tableName)

Returns a table instance for the given name. Note that this only represents the logic for the table, and does not fetch any information.

table.create([schema], [throughput], [cb])

Creates a table with the optionally specified schema and throughput.

The schema is specified as an object with a hash key and an optional range key, each with a name property and an optional type property that defaults to "String". If no schema is specified, {hash: {name: "id", type: "String }} is used.

The throughput is specified as an object with a read property and a write property, both defaulting to the minimum possible throughput (5 units).

This means that the following are identical:

table.create({id: "String"})
table.create({id: "String"}, {read: 5, write: 5})

This method returns the table description.


Fetches details about the table, which can include its status, size, schema, and other details, such as the following:

  name: 'DYNAMO_TEST_TABLE_3',
  createdAt: Mon, 30 Jan 2012 15:47:02 GMT,
  status: 'CREATING',
  schema: { hash: { name: 'id', type: 'String' } },
  throughput: { read: 5, write: 5 }


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.