dynobase-icon
Dynobase

DynamoDB with AWS SAM: Tables, Policies and Local Testing

Rafal Wilinski

Written by Rafal Wilinski

Last updated: October 23rd, 2026

Writing DynamoDB code by hand? Dynobase turns supported data operations into application code or scripts, and generates CDK, CloudFormation or Terraform for an existing table. Code generation in Dynobase

AWS SAM can create DynamoDB tables with AWS::Serverless::SimpleTable or the full AWS::DynamoDB::Table resource. Use SimpleTable for a single-attribute primary key; use Table when you need a sort key, indexes, TTL, deletion protection or other detailed settings. SAM policy templates connect your Lambda execution roles to the table, while the SAM CLI builds and tests the application.

Why use SAM with DynamoDB?

SAM extends CloudFormation with shorter declarations for Lambda functions, APIs and event sources. Deployment still runs through CloudFormation, so you can review changes, retain database resources and use ordinary AWS resources in the same template. SAM is infrastructure tooling, not a database service or an application authorization layer.

The example keeps the original book API: create a book, list books and delete a book. It uses Node.js 24, ES modules and SDK v3. AWS SDK for JavaScript v2 reached end of support on September 8, 2025, and old nodejs12.x examples should not be deployed.

Serverless Framework provides another YAML workflow, while AWS CDK synthesizes infrastructure from code. SAM is a practical choice when your team wants CloudFormation templates plus AWS-maintained local Lambda tooling.

Step 1: prepare the project

Install AWS CLI v2, SAM CLI, Docker and a supported Node.js release. Use an AWS profile for deployment:

Choose an AWS Quick Start Node.js project with the nodejs24.x runtime and ZIP packaging. Wizard menu numbers can change, so select by the displayed runtime name. For the files below, use a books directory beside template.yaml and initialize its runtime dependencies:

Remove or replace the sample Hello World resource in the generated template. The handler below is books/app.mjs; .mjs makes it an ES module without relying on the package's type field. Keep the dependency lock file and build with a current SAM CLI that supports the selected runtime.

SimpleTable versus AWS::DynamoDB::Table

A valid SimpleTable declaration uses a PrimaryKey object, not PrimaryKey: name:

Insert that under Resources in a SAM template. Without ProvisionedThroughput, SimpleTable generates on-demand billing. Its default key is a String named id if PrimaryKey is omitted. It supports PITR, encryption settings, tags and a table name, but it is intentionally narrower than the full resource. See the SimpleTable reference.

RequirementResource to use
Single partition key with basic settingsSimpleTable or Table
Partition key and sort keyTable
Global or local secondary indexesTable
TTL, Streams, throughput caps or deletion protectionTable
Multiple global-table replicasAWS::DynamoDB::GlobalTable

SAM templates can contain all these CloudFormation resources. Choosing the full Table does not prevent you from using SAM functions or policy templates alongside it.

Step 2: define the table and functions

Use this complete template.yaml for the walkthrough. It chooses the full Table to enable deletion protection:

SAM generates the REST API referenced by ServerlessRestApi from the Api events. Each function gets a separate execution role unless you supply one. The globals supply the same table name to all functions; permissions are configured separately.

When to use DynamoDBCrudPolicy

For a function that genuinely needs several table operations, SAM provides this shorthand inside the function's Properties:

It grants a group of data operations on the named table and its indexes. Pass the table name, not its ARN, because SAM constructs ARNs from the placeholder. It does not create the table or give the caller access to the HTTP API. The policy template list shows the exact generated actions.

Use DynamoDBReadPolicy for read-only functions, DynamoDBWritePolicy when the broader write group is appropriate, or an inline policy for one action as above. DynamoDBStreamReadPolicy concerns stream access, which is separate from table reads. If you supply an existing function Role, SAM does not add its Policies entries to that role; manage the role's policies yourself.

Step 3: implement create, list and delete

Start books/app.mjs with a shared SDK v3 client:

The local endpoint override uses dummy credentials; when it is empty in AWS, the SDK uses the Lambda execution role. Bundle the SDK packages rather than depending on the runtime's installed version.

Create a book

API Gateway sends event.body as a string, so parse it before accessing fields. The condition rejects an existing title rather than replacing it. A real catalog usually needs a stable ID because different books can share a title; the name key is retained here to keep the demonstration simple.

List a page of books

A Scan returns a page, not the entire database. Continue until the token is null. Limit controls evaluated items; filters can leave a short or empty page with another token. For a large catalog, model a Query access pattern instead of repeatedly scanning all books.

Delete a book

Use URL encoding for book names in request paths. DeleteItem is successful even when the item is already absent. Add a condition if your API needs a distinct not-found response.

Step 4: test SAM locally with DynamoDB Local

sam local runs Lambda code in Docker but does not create the DynamoDB table from your template. Run DynamoDB Local on a shared Docker network and create the table explicitly:

Create env.local.json:

The host CLI reaches the published localhost port. The SAM Lambda container reaches the other container by its network name, dynamodb-local; localhost inside the Lambda container would refer to itself.

Call http://127.0.0.1:3000/books with a JSON POST body, then GET and DELETE requests. For one function invocation, write an API event to event.json and run:

An example event is {"body":"{\"name\":\"DynamoDB Notes\",\"author\":\"Sam\",\"pages\":120}"}. The local invocation documentation explains environment overrides and event files.

This database is in memory and disappears when the container stops. For persistent Compose storage and more SDK configurations, see running DynamoDB locally. Local tests do not validate IAM, PITR, replication or real throughput limits.

Step 5: deploy and operate the API

Review the account, Region, generated IAM roles and change set. Keep the local endpoint override out of deployment configuration. The guided deployment can save non-secret settings in samconfig.toml; use separate stack names and configurations for development and production.

The example exposes unauthenticated demonstration routes. Before using real data, configure API authorization, enforce item ownership, validate field lengths and handle application errors consistently. Confirm both successful requests and denied requests in AWS; a local success cannot demonstrate the execution role's permissions.

Monitor API and Lambda errors plus DynamoDB throttles. Enable appropriate alarms, test backup restoration, and document how the application switches to a restored table. PITR restores into a new table and supports a 1-to-35-day recovery window; shortening it does not reduce the price.

Indexes, Streams and safe cleanup

Use AWS::DynamoDB::Table for GSIs or LSIs and declare their keys alongside the table keys. Secondary indexes store projected data and add storage and write costs; they do not give free alternative queries. GSIs can be added later, while LSIs must be defined at table creation.

For event-driven processing, enable DynamoDB Streams and attach a SAM DynamoDB event source to a subscriber function. A table's stream permissions differ from its CRUD permissions. Consumers must handle duplicate delivery; see the Streams guide for retry and failure handling.

sam delete removes the stack, but the Retain policies in this template preserve the table. Deletion protection also blocks direct deletion until explicitly disabled. Retained tables continue to incur charges. If the database has a longer lifecycle than the API, manage it in a dedicated CloudFormation stack and pass its name and ARN to the application stack.

Frequently Asked Questions

Does AWS SAM support DynamoDB tables?

Yes. Use SimpleTable for a single primary-key attribute, or ordinary DynamoDB CloudFormation resources for detailed table and replica settings. They can coexist with SAM functions in one template.

What is the correct SimpleTable PrimaryKey syntax?

PrimaryKey is an object with Name and Type, such as Name: name and Type: String. A scalar value such as PrimaryKey: name is invalid.

Does DynamoDBCrudPolicy create a table?

No. It generates data-access permissions for a function's execution role. Define the table separately and pass its name to the policy template.

Does sam local create DynamoDB automatically?

No. Start DynamoDB Local, create its table and configure the SDK endpoint. A shared Docker network lets the SAM Lambda container reach the database container by name.

Is SimpleTable on-demand by default?

Yes, when ProvisionedThroughput is omitted, SAM generates PAY_PER_REQUEST billing. The full AWS::DynamoDB::Table resource should set BillingMode explicitly.

Dynobase is a Professional GUI Client for DynamoDB

Start your 7-day free trial today

Product Features

Download
/
Pricing
/
Member Portal
/
Privacy
/
EULA
/
Twitter
© 2026 Dynobase