README.md
  1  # Amazon DynamoDB Construct Library
  2  <!--BEGIN STABILITY BANNER-->
  3  
  4  ---
  5  
  6  ![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge)
  7  
  8  ![cdk-constructs: Stable](https://img.shields.io/badge/cdk--constructs-stable-success.svg?style=for-the-badge)
  9  
 10  ---
 11  
 12  <!--END STABILITY BANNER-->
 13  
 14  Here is a minimal deployable DynamoDB table definition:
 15  
 16  ```ts
 17  const table = new dynamodb.Table(this, 'Table', {
 18    partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
 19  });
 20  ```
 21  
 22  ## Importing existing tables
 23  
 24  To import an existing table into your CDK application, use the `Table.fromTableName`, `Table.fromTableArn` or `Table.fromTableAttributes`
 25  factory method. This method accepts table name or table ARN which describes the properties of an already
 26  existing table:
 27  
 28  ```ts
 29  declare const user: iam.User;
 30  const table = dynamodb.Table.fromTableArn(this, 'ImportedTable', 'arn:aws:dynamodb:us-east-1:111111111:table/my-table');
 31  // now you can just call methods on the table
 32  table.grantReadWriteData(user);
 33  ```
 34  
 35  If you intend to use the `tableStreamArn` (including indirectly, for example by creating an
 36  `@aws-cdk/aws-lambda-event-source.DynamoEventSource` on the imported table), you *must* use the
 37  `Table.fromTableAttributes` method and the `tableStreamArn` property *must* be populated.
 38  
 39  ## Keys
 40  
 41  When a table is defined, you must define it's schema using the `partitionKey`
 42  (required) and `sortKey` (optional) properties.
 43  
 44  ## Billing Mode
 45  
 46  DynamoDB supports two billing modes:
 47  
 48  * PROVISIONED - the default mode where the table and global secondary indexes have configured read and write capacity.
 49  * PAY_PER_REQUEST - on-demand pricing and scaling. You only pay for what you use and there is no read and write capacity for the table or its global secondary indexes.
 50  
 51  ```ts
 52  const table = new dynamodb.Table(this, 'Table', {
 53    partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
 54    billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
 55  });
 56  ```
 57  
 58  Further reading:
 59  https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.
 60  
 61  ## Configure AutoScaling for your table
 62  
 63  You can have DynamoDB automatically raise and lower the read and write capacities
 64  of your table by setting up autoscaling. You can use this to either keep your
 65  tables at a desired utilization level, or by scaling up and down at pre-configured
 66  times of the day:
 67  
 68  Auto-scaling is only relevant for tables with the billing mode, PROVISIONED.
 69  
 70  [Example of configuring autoscaling](test/integ.autoscaling.lit.ts)
 71  
 72  Further reading:
 73  https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AutoScaling.html
 74  https://aws.amazon.com/blogs/database/how-to-use-aws-cloudformation-to-configure-auto-scaling-for-amazon-dynamodb-tables-and-indexes/
 75  
 76  ## Amazon DynamoDB Global Tables
 77  
 78  You can create DynamoDB Global Tables by setting the `replicationRegions` property on a `Table`:
 79  
 80  ```ts
 81  const globalTable = new dynamodb.Table(this, 'Table', {
 82    partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
 83    replicationRegions: ['us-east-1', 'us-east-2', 'us-west-2'],
 84  });
 85  ```
 86  
 87  When doing so, a CloudFormation Custom Resource will be added to the stack in order to create the replica tables in the
 88  selected regions.
 89  
 90  The default billing mode for Global Tables is `PAY_PER_REQUEST`.
 91  If you want to use `PROVISIONED`,
 92  you have to make sure write auto-scaling is enabled for that Table:
 93  
 94  ```ts
 95  const globalTable = new dynamodb.Table(this, 'Table', {
 96    partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
 97    replicationRegions: ['us-east-1', 'us-east-2', 'us-west-2'],
 98    billingMode: dynamodb.BillingMode.PROVISIONED,
 99  });
100  
101  globalTable.autoScaleWriteCapacity({
102    minCapacity: 1,
103    maxCapacity: 10,
104  }).scaleOnUtilization({ targetUtilizationPercent: 75 });
105  ```
106  
107  When adding a replica region for a large table, you might want to increase the
108  timeout for the replication operation:
109  
110  ```ts
111  const globalTable = new dynamodb.Table(this, 'Table', {
112    partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
113    replicationRegions: ['us-east-1', 'us-east-2', 'us-west-2'],
114    replicationTimeout: Duration.hours(2), // defaults to Duration.minutes(30)
115  });
116  ```
117  
118  ## Encryption
119  
120  All user data stored in Amazon DynamoDB is fully encrypted at rest. When creating a new table, you can choose to encrypt using the following customer master keys (CMK) to encrypt your table:
121  
122  * AWS owned CMK - By default, all tables are encrypted under an AWS owned customer master key (CMK) in the DynamoDB service account (no additional charges apply).
123  * AWS managed CMK - AWS KMS keys (one per region) are created in your account, managed, and used on your behalf by AWS DynamoDB (AWS KMS charges apply).
124  * Customer managed CMK - You have full control over the KMS key used to encrypt the DynamoDB Table (AWS KMS charges apply).
125  
126  Creating a Table encrypted with a customer managed CMK:
127  
128  ```ts
129  const table = new dynamodb.Table(this, 'MyTable', {
130    partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
131    encryption: dynamodb.TableEncryption.CUSTOMER_MANAGED,
132  });
133  
134  // You can access the CMK that was added to the stack on your behalf by the Table construct via:
135  const tableEncryptionKey = table.encryptionKey;
136  ```
137  
138  You can also supply your own key:
139  
140  ```ts
141  import * as kms from '@aws-cdk/aws-kms';
142  
143  const encryptionKey = new kms.Key(this, 'Key', {
144    enableKeyRotation: true,
145  });
146  const table = new dynamodb.Table(this, 'MyTable', {
147    partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
148    encryption: dynamodb.TableEncryption.CUSTOMER_MANAGED,
149    encryptionKey, // This will be exposed as table.encryptionKey
150  });
151  ```
152  
153  In order to use the AWS managed CMK instead, change the code to:
154  
155  ```ts
156  const table = new dynamodb.Table(this, 'MyTable', {
157    partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
158    encryption: dynamodb.TableEncryption.AWS_MANAGED,
159  });
160  
161  // In this case, the CMK _cannot_ be accessed through table.encryptionKey.
162  ```
163  
164  ## Get schema of table or secondary indexes
165  
166  To get the partition key and sort key of the table or indexes you have configured:
167  
168  ```ts
169  declare const table: dynamodb.Table;
170  const schema = table.schema();
171  const partitionKey = schema.partitionKey;
172  const sortKey = schema.sortKey;
173  
174  // In case you want to get schema details for any secondary index
175  // const { partitionKey, sortKey } = table.schema(INDEX_NAME);
176  ```
177  
178  ## Kinesis Stream
179  
180  A Kinesis Data Stream can be configured on the DynamoDB table to capture item-level changes.
181  
182  ```ts
183  import * as kinesis from '@aws-cdk/aws-kinesis';
184  
185  const stream = new kinesis.Stream(this, 'Stream');
186  
187  const table = new dynamodb.Table(this, 'Table', {
188    partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
189    kinesisStream: stream,
190  });
191  ```