Effortlessly Migrate DynamoDB Table to Global Table with CloudFormation and CDK: No Downtime, No data loss.

Sharon Diskin
3 min readFeb 3, 2023

To begin with, This article is most relevant for organizations that have a DynamoDB table associated with a CloudFormation stack and now wish to convert it into a global DynamoDB table with no downtime and no data loss.
CloudFormation templates generated with CDK are also included in this article.

In our effort to make our production environment multi-region in AWS, we aimed to transform our DynamoDB single-region tables into global tables. While this may seem like a simple task, similar to the manual way, just go the DynamoDB and under the “Global table” tab create a replica in another region, when working with a CloudFormation stack simply changing the AWS::DynamoDB::Table resource in the CloudFormation template to AWS::DynamoDB::GlobalTable was not a viable solution.Unfortunately, this approach would likely result in the deletion of our existing tables and the creation of new global tables, resulting in a complete loss of data. Given the significance of our data, this was not a scenario we could accept.

After conducting some research, we were fortunate to find a straightforward solution to achieve our goal. Our migration plan was as follows:

  1. We updated our CloudFormation template to include a “DeletionPolicy Retain” [1] for each resource.
    The “DeletionPolicy: Retain” ensures that even if the CloudFormation template is deleted, the resources associated with the stack will not be deleted.
  2. We deleted our DynamoDB stack.
    As a part of our migration plan, we carefully deleted our DynamoDB stack, resulting in a standalone regular DynamoDB table that was no longer associated with any provisioning too
  3. Under the “global table” tab in the DynamoDB console we created replicas in our failover regions. Our DyanmoDB table now became a global table.
    This action is easy and safe — there is no chance of data loss and no downtime (only some lags and slowness on the replicas while being created).
  4. With CDK, we generated a new CloudFormation template [1] for DynamoDB, designed specifically for global tables.
    The previous template, which defined a regular table, contained a resource of type AWS::DynamoDB::Table In contrast, the new template was structured around the AWS::DynamoDB::GlobalTabletype, and included a “Replicas” property to define all the replicas we had created.
    Replicas:
    - PointInTimeRecoverySpecification:
    PointInTimeRecoveryEnabled: true
    Region: us-east-1
    - PointInTimeRecoverySpecification:
    PointInTimeRecoveryEnabled: true
    Region: us-east-2
    - PointInTimeRecoverySpecification:
    PointInTimeRecoveryEnabled: true
    Region: eu-central-1

    * [2] Below you can see a full example of the before and after
  5. We created a new CloudFormation stack with the generated CloudFormation template that supports a global table. The new stack use the ”import existing resources” method rather than creating a new resource.
    On the CloudFormation console, under “Create Stack” you have the option to choose “with existing resources (import resources). We choose these options, uploaded the template, and filled in the name of the table we want to import.

Great! We successfully linked our DynamoDB global table to a CloudFormation stack that was generated using the AWS Cloud Development Kit (CDK). Every time we make changes to the code with the CDK, which updates the CloudFormation template and results in a deployment, our GlobalTable will reflect these updates.

Side notes:
[1]
In order to add a deletion policy, under the type add DeletionPolicy (indented the same in the same tab as the type):

MyDyanmoDBTable:
Type: AWS::DynamoDB::Table
DeletionPolicy: Retain

[2] To generate a global DynamoDB table using the CDK we used the “CfnGlobalTable” class, this is the preferred class to use since
the “GlobalTable” class generated a weird yaml with all kind of dependencies.

[3] Before:

  MyDyanmoDBTable:
Type: AWS::DynamoDB::Table
UpdateReplacePolicy: Retain
DeletionPolicy: Retain
Properties:
KeySchema:
- AttributeName: key
KeyType: HASH
AttributeDefinitions:
- AttributeName: key
AttributeType: S
BillingMode: PAY_PER_REQUEST
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
TableName: MyTable

After:

  MyDyanmoDBTable:
Type: AWS::DynamoDB::GlobalTable
UpdateReplacePolicy: Retain
DeletionPolicy: Retain
Properties:
AttributeDefinitions:
- AttributeName: key
AttributeType: S
KeySchema:
- AttributeName: key
KeyType: HASH
Replicas:
- PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
Region: us-east-1
- PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
Region: us-east-2
- PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
Region: eu-central-1
BillingMode: PAY_PER_REQUEST
TableName: MyTable

I hope this article is useful to you! If you require any assistance, please don’t hesitate to reach out to me at sharon.ad94@gmail.com. I am always happy to help :)

--

--

Sharon Diskin

A DevOps engineer at CloudBit with a strong desire to share my knowledge and document my experiences. I hope that you will find my atricles helpful :)