askill
aws-dynamodb

aws-dynamodbSafety 100Repository

Amazon DynamoDB integration with IAM authentication using @aws-sdk/client-dynamodb and @aws-sdk/lib-dynamodb. Use when implementing NoSQL database operations with DynamoDB.

0 stars
1.2k downloads
Updated 1/30/2026

Package Files

Loading files...
SKILL.md

Amazon DynamoDB Integration

Explore these example files to see a minimal implementation of Amazon DynamoDB in a Next.js application.

This is a simple TODO app that demonstrates how to connect to an Amazon DynamoDB database using awsCredentialsProvider authentication and perform basic CRUD operations.

Guidelines

  • Use the standard @aws-sdk/client-dynamodb and @aws-sdk/lib-dynamodb libraries for access.
  • Use the DynamoDB DocumentClient from @aws-sdk/lib-dynamodb with {removeUndefinedValues: true} for simplified data handling.
  • Use AWS IAM authentication via the awsCredentialsProvider from @vercel/functions/oidc using AWS_REGION and AWS_ROLE_ARN environment variables.
  • Use DYNAMODB_TABLE_NAME environment variable for the table name.
  • Use DYNAMODB_TABLE_PARTITION_KEY environment variable to get the partition key name for commands that require it.
  • Use parameterized expressions to prevent injection attacks.
  • NEVER use DynamoDB ORMs or third-party libraries for database access.

Dependencies

Required dependencies:

  • @vercel/functions/oidc
  • @aws-sdk/client-dynamodb
  • @aws-sdk/lib-dynamodb

Optional dependencies:

  • nanoid: for generating unique IDs
  • lucide-react: for UI components and icons
  • swr: for client-side data fetching

Directory Structure

app/
  api/
    todos/
      [id]/
        route.ts
      route.ts
  page.tsx
  layout.tsx
components/
  todo-app.tsx
lib/
  db.ts
  types.ts

DynamoDB Schema

This example uses a single DynamoDB table named todos with a single hash key attribute "id" of type String, and additional non-key attributes as needed.

Core Files

lib/db.ts

import { DynamoDBClient } from '@aws-sdk/client-dynamodb'
import {
  DynamoDBDocumentClient,
  PutCommand,
  GetCommand,
  ScanCommand,
  UpdateCommand,
  DeleteCommand,
} from '@aws-sdk/lib-dynamodb'
import { awsCredentialsProvider } from '@vercel/functions/oidc'
import { Todo } from './types'

export const TABLE_NAME = process.env.DYNAMODB_TABLE_NAME
const PK = process.env.DYNAMODB_TABLE_PARTITION_KEY || 'id'

const client = new DynamoDBClient({
  region: process.env.AWS_REGION,
  credentials: awsCredentialsProvider({
    roleArn: process.env.AWS_ROLE_ARN,
    clientConfig: { region: process.env.AWS_REGION },
  }),
})

const docClient = DynamoDBDocumentClient.from(client, {
  marshallOptions: {
    removeUndefinedValues: true,
  },
})

export async function getAllTodos(): Promise<Todo[]> {
  const result = await docClient.send(
    new ScanCommand({
      TableName: TABLE_NAME,
    }),
  )

  const todos = (result.Items || []) as Todo[]

  // Sort by createdAt descending
  return todos.sort((a, b) => b.createdAt - a.createdAt)
}

export async function getTodoById(id: string): Promise<Todo | null> {
  const result = await docClient.send(
    new GetCommand({
      TableName: TABLE_NAME,
      Key: { [PK]: id },
    }),
  )

  return (result.Item as Todo) || null
}

export async function createTodo(id: string, title: string): Promise<Todo> {
  const todo: Todo = {
    id,
    title,
    completed: false,
    createdAt: Date.now(),
  }

  await docClient.send(
    new PutCommand({
      TableName: TABLE_NAME,
      Item: { [PK]: id, ...todo },
    }),
  )

  return todo
}

export async function updateTodo(
  id: string,
  updates: { title?: string; completed?: boolean },
): Promise<Todo | null> {
  // Build the update expression dynamically
  const expressionParts: string[] = []
  const expressionAttributeNames: Record<string, string> = {}
  const expressionAttributeValues: Record<string, any> = {}

  if (updates.title !== undefined) {
    expressionParts.push('#title = :title')
    expressionAttributeNames['#title'] = 'title'
    expressionAttributeValues[':title'] = updates.title
  }

  if (updates.completed !== undefined) {
    expressionParts.push('#completed = :completed')
    expressionAttributeNames['#completed'] = 'completed'
    expressionAttributeValues[':completed'] = updates.completed
  }

  if (expressionParts.length === 0) {
    // No updates, just return the existing todo
    return getTodoById(id)
  }

  const result = await docClient.send(
    new UpdateCommand({
      TableName: TABLE_NAME,
      Key: { [PK]: id },
      UpdateExpression: `SET ${expressionParts.join(', ')}`,
      ExpressionAttributeNames: expressionAttributeNames,
      ExpressionAttributeValues: expressionAttributeValues,
      ReturnValues: 'ALL_NEW',
    }),
  )

  return (result.Attributes as Todo) || null
}

export async function deleteTodo(id: string): Promise<boolean> {
  await docClient.send(
    new DeleteCommand({
      TableName: TABLE_NAME,
      Key: { [PK]: id },
    }),
  )

  return true
}

lib/types.ts

export interface Todo {
  id: string
  title: string
  completed: boolean
  createdAt: number
}

Reference Files

FileDescription
references/examples/lib/db.tsDynamoDB client setup and CRUD operations
references/examples/lib/types.tsTypeScript type definitions
references/examples/app/api/todos/route.tsGET and POST handlers for todos
references/examples/app/api/todos/[id]/route.tsPATCH and DELETE handlers for individual todos
references/examples/app/page.tsxHome page component
references/examples/components/todo-app.tsxInteractive todo list component

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/11/2026

A comprehensive and highly actionable guide for integrating Amazon DynamoDB into a Next.js application using the AWS SDK v3 and IAM authentication.

100
95
90
95
98

Metadata

Licenseunknown
Version-
Updated1/30/2026
Publisherrand-tech

Tags

apici-cddatabase