Back to Blog
Lesson 16 of the AWS: AWS Core Services for Developers course
Cloud NativeJuly 16, 20264 min read

Connecting Lambda to DynamoDB: A Backend Logic Guide

Learn how to securely connect your Lambda functions to DynamoDB. We cover IAM permissions, the AWS SDK for Node.js, and implementing CRUD logic in your code.

AWSLambdaDynamoDBServerlessCloud NativeNode.js
Colorful lines of code on a computer screen showcasing programming and technology focus.

Previously in this course, we covered DynamoDB Data Modeling for Developers and mastered CRUD Operations with AWS SDK. Now that you understand how to structure your tables and interact with them via local scripts, it’s time to move that logic into the cloud.

In this lesson, we will integrate your backend logic with DynamoDB by running your code inside an AWS Lambda environment.

Granting Lambda Permission to Access DynamoDB

By default, a Lambda function is isolated. Even if you have the correct code to read or write to a database, the function will fail with an "Access Denied" error because it lacks the necessary Identity and Access Management (IAM) permissions.

To connect your function to DynamoDB, you must attach an IAM policy to the function's Execution Role. This follows the principle of least privilege: you grant the function only the actions it needs (e.g., dynamodb:PutItem or dynamodb:Query).

The Permission Workflow

  1. Identify the Role: Every Lambda function has an associated IAM role.
  2. Define the Policy: Create a JSON policy that allows dynamodb:PutItem and dynamodb:GetItem on your specific table ARN.
  3. Attach: Attach this policy to the function's role.

If you are using the AWS CDK as we have in previous lessons, this is handled automatically via the table.grantReadWriteData(function) method, which abstracts the IAM policy creation for you.

Writing a Function to Save User Input

Close-up of a hand touching a laptop keyboard with Arabic letters.

Now that permissions are handled, let's write the Lambda Integration logic. We will use the AWS SDK v3 for Node.js.

When you trigger a function (e.g., via an HTTP request), the event object contains your user input. We need to extract that data and pass it to the DynamoDB PutCommand.

JAVASCRIPT
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, PutCommand } = require("@aws-sdk/lib-dynamodb");

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

exports.handler = async (event) => {
    // 1. Parse input from the trigger event
    const body = JSON.parse(event.body);
    
    const params = {
        TableName: process.env.TABLE_NAME,
        Item: {
            userId: body.id,
            userName: body.name,
            timestamp: new Date().toISOString()
        }
    };

    try {
        // 2. Perform the save operation
        await docClient.send(new PutCommand(params));
        return { statusCode: 200, body: "Data saved successfully!" };
    } catch (error) {
        console.error(error);
        return { statusCode: 500, body: "Failed to save data." };
    }
};

Querying the Database from a Function

Retrieving data is just as straightforward as saving it. Instead of a PutCommand, you use the GetCommand or QueryCommand.

When querying, ensure your partition key matches the criteria exactly. In a serverless Backend Logic flow, you often receive the ID to search for directly from the URL path parameters or a query string.

JAVASCRIPT
const { GetCommand } = require("@aws-sdk/lib-dynamodb");

// Inside your handler
const params = {
    TableName: process.env.TABLE_NAME,
    Key: {
        userId: event.pathParameters.id
    }
};

const result = await docClient.send(new GetCommand(params));
return { 
    statusCode: 200, 
    body: JSON.stringify(result.Item) 
};

Hands-on Exercise

  1. Prepare your environment: Ensure your Lambda function has an environment variable named TABLE_NAME set to your DynamoDB table name.
  2. Write the code: Replace your existing function code with the PutCommand example provided above.
  3. Test: Use the Lambda console's "Test" feature to send a JSON payload containing {"id": "123", "name": "Test User"}.
  4. Verify: Check your DynamoDB table in the console to confirm the record was created.

Common Pitfalls

  • Missing Environment Variables: Forgetting to pass the TABLE_NAME into your function's configuration is the #1 cause of "ResourceNotFound" errors.
  • Timeouts: If your database calls take too long, your function will terminate. Ensure your Lambda timeout is set to at least 5-10 seconds for standard operations.
  • Cold Starts: Initializing the DynamoDBClient outside of the handler function (as shown in the code samples) is a best practice. It allows the client to be reused across warm invocations, significantly reducing latency.

FAQ

Q: Do I need to manage connection pools like in SQL databases? A: No. DynamoDB is an HTTP-based service. The AWS SDK handles the connection lifecycle for you.

Q: Should I use async/await for database operations? A: Yes. Since database operations are I/O bound, async/await ensures your function waits for the response before returning a success or failure status.

Q: Why is my function failing even though the code is correct? A: Check the CloudWatch logs. If you see a 403 Forbidden error, your IAM role is missing the necessary dynamodb permissions.

Recap

Wooden Scrabble tiles spelling 'RECAP' on a brown textured background. Text concept image.

You have now successfully bridged compute and storage. You learned how to grant your Lambda execution role the correct permissions, how to structure the AWS SDK to save user data, and how to query that data back. This connection forms the backbone of the Backend Logic for our serverless web app.

Up next: Handling DynamoDB Errors and Retries

Similar Posts