How to Use DynamoDB DocumentClient with Native JavaScript Types
The DynamoDB DocumentClient automatically converts native JavaScript types to DynamoDB's AttributeValue format and unmarshals query results back to plain objects, eliminating the need to manually construct { S: "...", N: "123" } structures.
Working with Amazon DynamoDB in the AWS SDK for JavaScript v3 becomes significantly more intuitive when you use the DynamoDB DocumentClient with native JavaScript types. This high-level abstraction, available in the @aws-sdk/lib-dynamodb package, bridges the gap between DynamoDB's underlying type system and idiomatic JavaScript code. According to the aws/agent-toolkit-for-aws repository, this approach is the recommended way to handle automatic marshalling while maintaining full type safety and supporting advanced features like pagination and large number handling.
What Is DynamoDB DocumentClient?
The DynamoDB DocumentClient is a high-level helper that wraps the low-level DynamoDBClient from @aws-sdk/client-dynamodb. While the underlying client handles HTTP transport, request signing, retries, and pagination, the DocumentClient adds a transformation layer that intercepts command inputs and outputs.
This architecture allows you to work with plain JavaScript objects, arrays, and primitives rather than the verbose AttributeValue structures required by the base client. The DocumentClient is type-safe and ships with full TypeScript definitions, enabling your editor to infer the shape of Item objects and command inputs.
How Automatic Marshalling Works
The DocumentClient processes data through two distinct phases as documented in skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md:
-
Marshalling – When sending commands, the client converts JavaScript primitives, arrays, objects, and
Sets into appropriate DynamoDB types (S,N,BOOL,L,M, etc.) based on a static mapping table【/cache/repos/github.com/aws/agent-toolkit-for-aws/main/skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md#L32-L43】. -
Unmarshalling – Responses are transformed back into native JavaScript values. By default, numbers become JavaScript
numberprimitives, though you can enablewrapNumbersto receiveNumberValueobjects for arbitrary-precision arithmetic【/cache/repos/github.com/aws/agent-toolkit-for-aws/main/skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md#L55-L57】.
Configuration Options for Marshalling
You can customize the transformation behavior via marshallOptions and unmarshallOptions when instantiating the client:
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
const client = DynamoDBDocumentClient.from(new DynamoDBClient({}), {
marshallOptions: {
removeUndefinedValues: true, // Drop undefined fields automatically
convertEmptyValues: false, // Preserve empty strings as-is
},
unmarshallOptions: {
wrapNumbers: true, // Return NumberValue instead of number
},
});
These options are documented in the "Marshall Options" section of the DynamoDB reference file【/cache/repos/github.com/aws/agent-toolkit-for-aws/main/skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md#L47-L55】.
Working with Large Numbers and Binary Data
By default, DynamoDB numbers are unmarshalled to JavaScript numbers. For values exceeding Number.MAX_SAFE_INTEGER, use the NumberValue class:
import { NumberValue, DynamoDBDocumentClient, PutCommand } from "@aws-sdk/lib-dynamodb";
const client = DynamoDBDocumentClient.from(new DynamoDBClient({}));
await client.send(
new PutCommand({
TableName: "MyTable",
Item: {
id: "1",
bigNum: NumberValue.from("1000000000000000000000.000000001"),
},
})
);
This approach ensures precision for financial or scientific data without losing fractional components. The DocumentClient also handles Set and binary data types automatically, converting them to native JavaScript Set objects and Uint8Array buffers respectively【/cache/repos/github.com/aws/agent-toolkit-for-aws/main/skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md#L60-L70】.
Paginating Results with DocumentClient
The DocumentClient integrates with the SDK's paginator utilities to handle LastEvaluatedKey automatically:
import { paginateScan } from "@aws-sdk/lib-dynamodb";
for await (const page of paginateScan({ client }, { TableName: "MyTable", Limit: 100 })) {
console.log(page.Items);
}
This pattern eliminates manual pagination logic while working with native JavaScript types throughout the iteration【/cache/repos/github.com/aws/agent-toolkit-for-aws/main/skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md#L82-L89】.
Complete CRUD Implementation Examples
The following example demonstrates creating, reading, querying, and deleting items using native JavaScript types:
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
DynamoDBDocumentClient,
PutCommand,
GetCommand,
QueryCommand,
DeleteCommand,
} from "@aws-sdk/lib-dynamodb";
const client = DynamoDBDocumentClient.from(
new DynamoDBClient({ region: "us-east-1" })
);
// Create - native JS types are marshaled automatically
await client.send(
new PutCommand({
TableName: "MyTable",
Item: { id: "1", name: "Alice", age: 30, active: true },
})
);
// Read
const { Item } = await client.send(
new GetCommand({ TableName: "MyTable", Key: { id: "1" } })
);
console.log(Item); // { id: '1', name: 'Alice', age: 30, active: true }
// Query with simple expressions
const { Items } = await client.send(
new QueryCommand({
TableName: "MyTable",
KeyConditionExpression: "id = :id",
ExpressionAttributeValues: { ":id": "1" },
})
);
// Delete
await client.send(
new DeleteCommand({ TableName: "MyTable", Key: { id: "1" } })
);
This implementation mirrors the canonical examples found in skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md【/cache/repos/github.com/aws/agent-toolkit-for-aws/main/skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md#L7-L28】.
Summary
- DynamoDBDocumentClient from
@aws-sdk/lib-dynamodbeliminates the need to manually construct AttributeValue structures when working with DynamoDB. - Automatic marshalling handles JavaScript objects, arrays, Sets, and binary data, with configurable options for undefined values and empty strings.
- Large number support requires enabling
wrapNumbersand using theNumberValueclass for values exceeding JavaScript's safe integer range. - Native pagination is available through
paginateScanandpaginateQueryfunctions that maintain type safety throughout result sets.
Frequently Asked Questions
What is the difference between DynamoDBClient and DynamoDBDocumentClient?
DynamoDBClient is the low-level client requiring manual { S: "value" } AttributeValue structures, while DynamoDBDocumentClient wraps it to automatically marshal native JavaScript types. The DocumentClient uses the same underlying HTTP transport and signing mechanisms but intercepts commands to transform inputs and outputs according to the mapping defined in skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md.
How do I handle undefined values in JavaScript objects?
Configure marshallOptions.removeUndefinedValues: true when creating the DocumentClient. As documented in the aws/agent-toolkit-for-aws reference files, this option strips undefined fields from objects before sending them to DynamoDB, preventing validation errors that occur when undefined values are present in the Item.
Can DynamoDB DocumentClient handle numbers larger than Number.MAX_SAFE_INTEGER?
Yes. Enable unmarshallOptions.wrapNumbers: true to receive NumberValue objects instead of primitive numbers. For writes, explicitly construct NumberValue.from("...") with the string representation of your large number, as shown in the large-number handling section of skills/core-skills/aws-sdk-js-v3-usage/references/dynamodb.md.
How do I paginate results without writing manual loops?
Use the paginateScan or paginateQuery functions exported by @aws-sdk/lib-dynamodb. These async generators yield pages of results and automatically handle the LastEvaluatedKey/ExclusiveStartKey pattern, allowing you to iterate with for await...of as demonstrated in the pagination examples within the repository.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →