TypeScript icon, indicating that this package has built-in type declarations

    2.10.1 • Public • Published

    Build Status npm version Semantic Release enabled Renovate enabled


    Typescript ORM of DynamoDB, written from scratch to fully support DynamoDB. Powering Vingle


    1. Serialize / Deserialize DynamoDB record -> TS class object based on annotations.
    2. Table Configurations
      • CreateTable
        • Create secondary indexes (Both local / global)
        • Configure TTL
      • DropTable
    3. PrimaryKey
      • FullPrimaryKey (Hash, Range)
      • HashPrimaryKey (Hash)
    4. Indexes
      • Local, both hash and range key
      • Global, both hash and range key
    5. Attribute
      • Type Support (Number / String / Boolean / Array / Object / Buffer)
      • TimeToLive
    6. DAX Support
      • You can specify this by setting the connection of table.
    7. Optimized aws-sdk usage
      • aws-sdk has a serious problem of not reusing HTTP connection towards DynamoDB by default. check this issue
      • this could cause unbearable latency sometimes with showing > 100ms. it's more of an issue of NodeJS HTTP module but nevertheless, it has been optimized here by keep-alive Code
    8. AWS X-Ray support
      • XRay is serverless distributed tracing service. In order to log DynamoDB transaction into it, you also need to some sort of risk monkey-patching. Here you can turn it on by setting process.env.ENABLE_XRAY = "true"
    9. Testing
      • You can change the endpoint of DynamoDB by setting the environment variable or setting new connection, So you can install local-dynamo locally at setup endpoint to local. refer package.json for the detailed how-to

    Also, dynamo-types let you overcome several limits that DynamoDB or the aws-sdk has.

    1. BatchWrite (batchDelete / batchPut) has a limit of a maximum of 25 items per request.
      • dynamo-types automatically splits given items into chunks of 25 and sends requests in parallel
    2. BatchGet has a limit of a maximum of 100 items per requests
      • dynamo-types automatically splits given keys to chunks of 100 and sends requests in parallel
    3. BatchGet doesn't keep the order of items as it is in input keys,
      • dynamo-types sort return items based on input keys
    4. BatchGet doesn't handle "missing items".
      • dynamo-types has "BatchGet" / "BatchGetFull"
        • BatchGet
          order items follow to keys, missing items are just missing. return type Promise<Array>
          so keys.legnth !== items.keys in this case
        • BatchGetFull
          order items follow to keys, fill missing items with "null". return type Promise<Array<Item | null>>
          so keys.length === items.keys always true

    And most importantly, all of those queries regardless of whether it's from index or primary key, strongly typed. I mean what's the point of using typescript if not anyway?


      @Decorator.Table({ name: "prod-Card" })
      class Card extends Table {
        public id: number;
        public title: string;
        @Decorator.Attribute({ timeToLive: true })
        public expiresAt: number;
        @Decorator.FullPrimaryKey('id', 'title')
        static readonly primaryKey: Query.FullPrimaryKey<Card, number, string>;
        static readonly writer: Query.Writer<Card>;
      // Create Table At DynamoDB
      await Card.createTable();
      // Drop Table At DynamoDB
      await Card.dropTable();
      // Creating Record
      const card = new Card();
      card.id = 100;
      card.title = "Title";
      await Card.writer.put(card);
      // OR just
      await card.save();
      // Batch Put
      await Card.writer.batchPut([
        new Card(),
        new Card()
      // Get Record
      await Card.primaryKey.get(100, "Title");
      // BatchGet
      // This array is strongly typed such as Array<[number, string]> so don't worry.
      await Card.primaryKey.batchGet([
        [100, "Title"],
        [200, "Title2"]
      // Query
      // Range key opreations are stringly typed. ([">=", T] | ["=", T] ...)
      await Card.primaryKey.query({
        hash: 100,
        range: [">=", "Title"]
      // Delete record
      await card.delete()
      // Delete record only when it meets condition.
      // with this, you can avoid race condition such as somebody updating the record while you're trying to delete it
      await card.delete({
        condition: { title: Equal("Title") }
      // when mismatch occurs, it raises "ConditionalCheckFailedException" error.
      // Likewise, update record only when it meets condition
      card.title = "New Title"
      await card.save({ condition: { title: "Title" } });
      // when mismatch occurs, it raises "ConditionalCheckFailedException" error.
    import {
    } from "dynamo-types";
    @Decorator.Table({ name: `table_name` })
    export class CardStat extends Table {
      public static readonly primaryKey: Query.HashPrimaryKey<CardStat, number>;
      public static readonly writer: Query.Writer<CardStat>;
      @Decorator.Attribute({ name: "card_id" })
      public cardId: number;
      @Decorator.Attribute({ name: "impressions_count" })
      public impressionsCount: number = 0;
      @Decorator.Attribute({ name: "shares" })
      public shares: number = 0;

    TS Compiler Setting

    DynamoTypes utilize reflect-metadata to read metadata (usually type of variables) from Typescript code. to do so, you must enable those options.

        "compilerOptions": {
            // other options..
            "experimentalDecorators": true, // required
            "emitDecoratorMetadata": true // required


    DynamoDB supports 2 different kinds of connections. Plain connections to DynamoDB through HTTP, or through DAX. dynamo-types supports this by letting you create a separate connection for each table.

    @Decorator.Table({ name: "prod-Card1", connection: new DAXConnection({ endpoints: ["dax-domain:8892"] }) })
    class Card extends Table {
      public id: number;
      public title: string;
      @AttributeDecorator({ name: "complicated_field"})
      public complicatedField: string;
      @FullPrimaryKeyDecorator('id', 'title')
      static readonly primaryKey: Query.FullPrimaryKey<Card, number, string>;
      static readonly writer: Query.Writer<Card>;

    Then any query that is sent to the Card table will be sent through DAXConnection.

    If you don't specify any connection, it automatically uses default connection, which is DynamoDBConnection.




    npm i dynamo-types

    DownloadsWeekly Downloads






    Unpacked Size

    152 kB

    Total Files


    Last publish


    • kurtlee