Skip to main content
RapidDev - Software Development Agency
lovable-integrationsEdge Function Integration

How to Integrate Lovable with Amazon DynamoDB

Connect Amazon DynamoDB to Lovable by creating an Edge Function that uses the AWS SDK v3 with IAM access key credentials stored in Cloud Secrets. The function handles DynamoDB table operations — GetItem, PutItem, Query, Scan — and returns data to your React frontend. Use this when your app is part of the AWS ecosystem or needs DynamoDB's key-value performance at scale.

What you'll learn

  • How to set up IAM credentials with scoped DynamoDB permissions for Lovable Edge Functions
  • How to use AWS SDK v3 DynamoDB commands in a Deno Edge Function environment
  • How to perform GetItem, PutItem, Query, and Scan operations from a Lovable app
  • How DynamoDB's partition key and sort key model affects how you query data
  • When to use DynamoDB versus Lovable's built-in Supabase PostgreSQL for new projects
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate15 min read40 minutesDatabaseMarch 2026RapidDev Engineering Team
TL;DR

Connect Amazon DynamoDB to Lovable by creating an Edge Function that uses the AWS SDK v3 with IAM access key credentials stored in Cloud Secrets. The function handles DynamoDB table operations — GetItem, PutItem, Query, Scan — and returns data to your React frontend. Use this when your app is part of the AWS ecosystem or needs DynamoDB's key-value performance at scale.

Connect Amazon DynamoDB to Your Lovable App via AWS SDK v3

Amazon DynamoDB is the database of choice for AWS-native applications — it scales automatically, requires no server management, and delivers consistent performance regardless of data volume. If your application already lives in the AWS ecosystem, or if you need DynamoDB's specific strengths like automatic global replication, time-to-live expiration, or point-in-time recovery, integrating it with Lovable is straightforward through an Edge Function.

The integration uses the AWS SDK v3, which is compatible with Deno's npm module support. Your Edge Function initializes a DynamoDB client with IAM credentials from Cloud Secrets, then executes typed commands from the @aws-sdk/client-dynamodb or @aws-sdk/lib-dynamodb packages. The DocumentClient from lib-dynamodb handles marshaling and unmarshaling DynamoDB's attribute value format automatically, making the code cleaner than working with the lower-level client directly.

The key DynamoDB concept to understand before building is the difference between Query and Scan. Query operations are fast and efficient — they retrieve items by partition key and optionally sort key range. Scan operations read every item in the table to find matches, which is slow and expensive on large tables. For a good Lovable integration, design your table with the access patterns you need upfront: which fields you'll filter by become your partition keys or GSI (Global Secondary Index) partition keys.

Integration method

Edge Function Integration

Amazon DynamoDB connects to Lovable through an Edge Function that uses the AWS SDK v3 DynamoDB client. IAM access key and secret are stored in Cloud Secrets, and all table operations — reads, writes, queries, and scans — route through the Edge Function so AWS credentials never reach the browser.

Prerequisites

  • A Lovable account with a project open and Lovable Cloud enabled
  • An AWS account with at least one DynamoDB table created
  • An IAM user or role with dynamodb:GetItem, dynamodb:PutItem, dynamodb:Query, dynamodb:Scan, and dynamodb:UpdateItem permissions on your specific table
  • Your IAM Access Key ID and Secret Access Key with the DynamoDB permissions
  • Knowledge of your DynamoDB table's partition key and sort key names and types

Step-by-step guide

1

Create an IAM User with Scoped DynamoDB Permissions

Never use root AWS credentials or overly broad IAM roles for your Lovable Edge Function. Create a dedicated IAM user with precisely the permissions your app needs. Log in to the AWS Console and navigate to IAM → Users → Create user. Name it something descriptive like lovable-dynamodb-user. On the permissions step, choose 'Attach policies directly' and click 'Create policy'. In the JSON editor, paste a policy that grants access only to your specific table. Use the table's ARN (Amazon Resource Name) which looks like: arn:aws:dynamodb:us-east-1:123456789012:table/MyTableName. The minimum permissions for a read-write integration are: dynamodb:GetItem, dynamodb:PutItem, dynamodb:UpdateItem, dynamodb:DeleteItem, dynamodb:Query, dynamodb:Scan on the table ARN, plus dynamodb:Query on any Global Secondary Index ARNs (format: arn:aws:dynamodb:region:account:table/MyTable/index/*) if your app uses GSIs. After creating the policy and attaching it to the user, go to the user's Security credentials tab and click 'Create access key'. Select 'Application running outside AWS' as the use case. Copy the Access Key ID and Secret Access Key — the secret is shown only once. Keep them ready for the next step.

Pro tip: The principle of least privilege applies here. If your Lovable app only reads from DynamoDB, grant only dynamodb:GetItem, dynamodb:Query, and dynamodb:Scan. Omitting write permissions entirely prevents accidental data mutation from a frontend bug or prompt injection.

Expected result: An IAM user exists with a scoped DynamoDB policy. You have the Access Key ID and Secret Access Key for the next step.

2

Add AWS Credentials to Cloud Secrets

In Lovable, click the '+' button next to the Preview panel to open the Cloud tab, then navigate to Secrets. Add these three secrets: - AWS_ACCESS_KEY_ID: the Access Key ID from the IAM user you just created - AWS_SECRET_ACCESS_KEY: the Secret Access Key for that IAM user - AWS_REGION: the AWS region where your DynamoDB table is located (e.g., us-east-1, eu-west-1, ap-southeast-1) The region must exactly match the region shown in your DynamoDB table's ARN. An incorrect region is a common cause of 'ResourceNotFoundException' errors when the Edge Function tries to access the table. Optionally, also add AWS_DYNAMODB_TABLE as a secret containing your primary table name. This makes it easy to switch between development and production tables by changing a single secret rather than redeploying Edge Function code. Never paste these credentials in the Lovable chat panel — Lovable's platform blocks approximately 1,200 hardcoded API keys daily, but free tier chat history is publicly visible.

Pro tip: Create separate IAM users and Cloud Secret sets for your development and production environments. This way, a mistake in your dev Lovable project cannot accidentally modify production DynamoDB data.

Expected result: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION are saved in Cloud Secrets. Your Edge Functions can now make authenticated DynamoDB calls.

3

Create the DynamoDB Edge Function

Create the Edge Function that handles DynamoDB operations. The AWS SDK v3 for DynamoDB is importable in Deno using the npm: prefix, and the @aws-sdk/lib-dynamodb package's DynamoDBDocumentClient automatically handles DynamoDB's attribute value marshaling (converting between JavaScript types and DynamoDB's { S: 'string' }, { N: '123' } format). The Edge Function should initialize the DynamoDB client using credentials from environment variables, accept an operation type and table-specific parameters from the frontend, and return clean JSON responses. Supporting the four core operations covers most use cases: get (single item by key), put (create or replace item), query (items by partition key with optional sort key conditions), and scan (filter across all items — use sparingly). The most important DynamoDB concept in the code is the KeyConditionExpression for Query operations. A query always requires a partition key equality condition (pkField = :pkValue) and can optionally include a sort key range condition (skField BETWEEN :start AND :end). Use ExpressionAttributeNames for field names that are DynamoDB reserved words (like 'status', 'name', 'type') and ExpressionAttributeValues for the actual values.

Lovable Prompt

Create an Edge Function called dynamodb-proxy at supabase/functions/dynamodb-proxy/index.ts using the AWS SDK v3. Import DynamoDBClient from npm:@aws-sdk/client-dynamodb and DynamoDBDocumentClient, GetCommand, PutCommand, QueryCommand, ScanCommand, UpdateCommand from npm:@aws-sdk/lib-dynamodb. Initialize the client with credentials from Deno.env.get for AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION. Accept POST requests with: operation (get, put, query, scan, update), tableName (string), key (object with partition and sort key values for get), item (object for put), partitionKey (object with keyName and keyValue for query), sortKeyCondition (optional object with operator and value for query), filterExpression (optional string for scan), limit (optional number). Return the items array and count. Include CORS headers.

Paste this in Lovable chat

supabase/functions/dynamodb-proxy/index.ts
1// supabase/functions/dynamodb-proxy/index.ts
2import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
3import { DynamoDBClient } from "npm:@aws-sdk/client-dynamodb";
4import {
5 DynamoDBDocumentClient,
6 GetCommand,
7 PutCommand,
8 QueryCommand,
9 ScanCommand,
10 UpdateCommand,
11} from "npm:@aws-sdk/lib-dynamodb";
12
13const corsHeaders = {
14 "Access-Control-Allow-Origin": "*",
15 "Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
16 "Access-Control-Allow-Methods": "POST, OPTIONS",
17};
18
19serve(async (req: Request) => {
20 if (req.method === "OPTIONS") {
21 return new Response("ok", { headers: corsHeaders });
22 }
23
24 try {
25 const client = new DynamoDBClient({
26 region: Deno.env.get("AWS_REGION"),
27 credentials: {
28 accessKeyId: Deno.env.get("AWS_ACCESS_KEY_ID") || "",
29 secretAccessKey: Deno.env.get("AWS_SECRET_ACCESS_KEY") || "",
30 },
31 });
32 const docClient = DynamoDBDocumentClient.from(client);
33
34 const { operation, tableName, key, item, partitionKey, sortKeyCondition, limit = 50 } = await req.json();
35
36 let result;
37
38 if (operation === "get") {
39 const response = await docClient.send(new GetCommand({ TableName: tableName, Key: key }));
40 result = { item: response.Item };
41 } else if (operation === "put") {
42 await docClient.send(new PutCommand({ TableName: tableName, Item: item }));
43 result = { success: true };
44 } else if (operation === "query" && partitionKey) {
45 const response = await docClient.send(new QueryCommand({
46 TableName: tableName,
47 KeyConditionExpression: "#pk = :pkVal",
48 ExpressionAttributeNames: { "#pk": partitionKey.keyName },
49 ExpressionAttributeValues: { ":pkVal": partitionKey.keyValue },
50 Limit: limit,
51 }));
52 result = { items: response.Items, count: response.Count };
53 } else if (operation === "scan") {
54 const response = await docClient.send(new ScanCommand({ TableName: tableName, Limit: limit }));
55 result = { items: response.Items, count: response.Count };
56 } else {
57 return new Response(
58 JSON.stringify({ error: `Unsupported operation: ${operation}` }),
59 { status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
60 );
61 }
62
63 return new Response(JSON.stringify(result), {
64 status: 200,
65 headers: { ...corsHeaders, "Content-Type": "application/json" },
66 });
67 } catch (error) {
68 return new Response(
69 JSON.stringify({ error: error.message }),
70 { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
71 );
72 }
73});

Pro tip: The DynamoDBDocumentClient handles JavaScript ↔ DynamoDB attribute format conversion automatically. Without it, you'd need to write { S: 'value' } for strings and { N: '42' } for numbers. Always prefer the DocumentClient over the base DynamoDBClient.

Expected result: The dynamodb-proxy Edge Function is deployed in Cloud → Edge Functions. The function can accept DynamoDB operation requests and return items from your tables.

4

Build Frontend Components for DynamoDB Data

With the Edge Function running, open the Lovable chat and describe the UI components you need. Tell Lovable your DynamoDB table structure — table name, partition key name and type, sort key name and type (if any), and the attribute names you want to display. Providing the access patterns upfront is important for DynamoDB: tell Lovable how users will filter the data. 'List all items by userId' is a Query operation (efficient). 'List all items where status is active' is a Scan with filter (slow on large tables, but acceptable for small tables or infrequent admin queries). If you need to filter on a non-key attribute frequently, mention that you may want a Global Secondary Index — Lovable can describe what GSI to create, though you'll need to create it in the AWS DynamoDB Console. When Lovable generates the React components, they call the dynamodb-proxy Edge Function with the operation and parameters. The loading state, error handling, and data display are generated automatically. For list views, tell Lovable to implement the lastEvaluatedKey-based DynamoDB pagination — DynamoDB does not support offset-based pagination, and Lovable needs to know this to generate correct 'Load more' functionality.

Lovable Prompt

Using the dynamodb-proxy Edge Function, build a customer management page. My DynamoDB table is Customers with partition key customerId (String). Items have: name (String), email (String), plan (String: 'free', 'pro', 'enterprise'), signedUpAt (String ISO8601), lastLoginAt (String ISO8601), totalSpend (Number). The table has a GSI called plan-index with partition key plan. Build: a searchable customer table that queries by plan using the GSI, customer count badges per plan at the top, and a customer detail modal showing all fields when a row is clicked.

Paste this in Lovable chat

Pro tip: DynamoDB Scan operations read every table item and are expensive. Avoid using them in real-time UI components. If you need to filter by attributes other than the partition key, add a Global Secondary Index in the AWS DynamoDB Console and use Query against that index instead.

Expected result: A customer management page loads in your Lovable app, showing customers from DynamoDB organized by plan. Clicking a customer opens a detail modal with all fields.

5

Test DynamoDB Operations and Verify Data Integrity

Test all CRUD operations in your Lovable app. Create a new item, verify it appears in the DynamoDB Console, update a field, and delete it. Check Cloud → Logs to see the Edge Function output for each operation. Verify the key design works for your access patterns. If queries are returning unexpected results, the most common cause is a mismatch between the partition key value in your query and the actual value stored in DynamoDB. DynamoDB key comparisons are case-sensitive and type-sensitive — the string '123' and the number 123 are different partition key values. Also test pagination. If your table has more than 50 items (the default limit in the Edge Function), the response includes a LastEvaluatedKey field. Your frontend needs to pass this back as the ExclusiveStartKey in the next request to get the next page. Ask Lovable to add 'Load more' pagination that uses this DynamoDB cursor pattern. For production deployments, review your IAM policy one more time. If any test revealed that the Edge Function needs additional permissions (like dynamodb:DescribeTable for table introspection), add only those specific permissions to the IAM policy rather than broadening to a managed policy like AmazonDynamoDBFullAccess.

Lovable Prompt

Review the dynamodb-proxy Edge Function integration for potential issues. Check that: all operations use the DocumentClient for automatic marshaling, error messages from AWS are properly caught and returned as JSON rather than crashing the function, and list operations include DynamoDB's LastEvaluatedKey for cursor-based pagination. Then add a 'Load more' button to the customer table that passes the LastEvaluatedKey from the previous response to fetch the next page.

Paste this in Lovable chat

Expected result: All DynamoDB operations work end-to-end. Creating, reading, and updating items in Lovable is reflected immediately in the AWS DynamoDB Console. Pagination works correctly for tables with many items.

Common use cases

Build a user session store and activity feed with DynamoDB

Your app already uses DynamoDB for session management and user activity logs. A Lovable admin dashboard calls DynamoDB to display active sessions, recent user actions, and audit trails. The partition key is userId and the sort key is timestamp, enabling efficient range queries for activity history.

Lovable Prompt

I have a DynamoDB table called UserActivity with partition key userId (String) and sort key timestamp (String ISO8601). Items have fields: action (String), resourceType (String), resourceId (String), ipAddress (String), success (Boolean). I've stored AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION in Cloud Secrets. Create an Edge Function called dynamodb-proxy that queries UserActivity by userId and optional date range. Then build an admin page showing the last 50 actions for a selected user with action type badges and success/failure indicators.

Copy this prompt to try it in Lovable

Display a product catalog from DynamoDB in a Lovable storefront

Your product catalog is stored in DynamoDB with category as the partition key and productId as the sort key. A Lovable-built catalog page queries products by category and displays them in a grid with filtering and sorting.

Lovable Prompt

I have a DynamoDB table called Products with partition key category (String) and sort key productId (String). Items have: name, description, price (Number), imageUrl, stock (Number), featured (Boolean). AWS credentials are stored in Cloud Secrets as AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION. Create an Edge Function for querying products by category, getting a single product by category + productId, and updating stock. Then build a product catalog page with category tabs, product cards, price display, and stock indicators.

Copy this prompt to try it in Lovable

Sync IoT device telemetry from DynamoDB to a monitoring dashboard

IoT devices write telemetry data to DynamoDB with deviceId as the partition key and a timestamp sort key. A Lovable monitoring dashboard reads the latest readings per device and displays charts of historical data.

Lovable Prompt

I have a DynamoDB table called DeviceTelemetry with partition key deviceId (String) and sort key recordedAt (String). Items include temperature (Number), humidity (Number), batteryLevel (Number), status (String). Using AWS credentials from Cloud Secrets, create an Edge Function that queries the last 24 hours of readings for a given deviceId. Then build a monitoring dashboard with device selector, current readings cards, and a line chart of temperature over the past 24 hours using Recharts.

Copy this prompt to try it in Lovable

Troubleshooting

Edge Function returns 'ResourceNotFoundException: Requested resource not found'

Cause: The table name or AWS region in the request does not match the actual DynamoDB table. DynamoDB table names and regions are exact-match — even a trailing space or wrong capitalization causes this error.

Solution: Open the AWS DynamoDB Console and navigate to Tables. Verify the exact table name (case-sensitive) and the region shown in the table's ARN. Compare these to the AWS_REGION secret in Lovable's Cloud Secrets and the tableName parameter being sent from your frontend. A region mismatch is the most common cause — for example, using us-east-1 when the table is in eu-west-1.

AWS SDK throws 'CredentialsProviderError: Could not load credentials from any providers'

Cause: One or more AWS credential secrets are missing or empty in Cloud Secrets. The AWS SDK v3 tries multiple credential providers and throws this error when all fail.

Solution: Open Cloud tab → Secrets and verify that AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION are all present with non-empty values. Check the secret names character by character — the SDK looks for exactly these names when credentials are passed explicitly. Temporarily add console.log statements to confirm the values are being read: console.log('Region:', Deno.env.get('AWS_REGION')). Remember to remove these logs after debugging.

typescript
1// Add temporary debug logging to verify credentials are loaded
2const region = Deno.env.get("AWS_REGION");
3const accessKeyId = Deno.env.get("AWS_ACCESS_KEY_ID");
4console.log("Region:", region);
5console.log("Key ID present:", !!accessKeyId && accessKeyId.startsWith("AKIA"));

Query returns empty Items array even though matching items exist in DynamoDB

Cause: The partition key name or value in the QueryCommand does not exactly match the DynamoDB table's actual partition key attribute name. DynamoDB is case-sensitive for attribute names.

Solution: In the AWS DynamoDB Console, open the table and check the exact attribute name for the partition key under Table → Overview → Partition key. This name must match exactly in your ExpressionAttributeNames and KeyConditionExpression. Also verify the key value type — if the partition key is a String, ensure you're passing a string, not a number.

DynamoDB Scan operation is very slow or times out on a large table

Cause: DynamoDB Scan reads every item in the table, which is slow and expensive for tables with thousands or millions of items. Edge Functions time out after 60 seconds by default.

Solution: Replace Scan with Query against a Global Secondary Index (GSI) for any frequently used filter patterns. In the AWS DynamoDB Console, go to your table → Indexes → Create index to add a GSI on the attribute you're filtering by. Then update your Edge Function to query the GSI using IndexName in the QueryCommand. For admin-only operations where Scan is acceptable, add a conservative Limit (100-200 items) and implement cursor-based pagination with LastEvaluatedKey.

typescript
1// Use GSI Query instead of Scan
2const response = await docClient.send(new QueryCommand({
3 TableName: tableName,
4 IndexName: "plan-index", // GSI name
5 KeyConditionExpression: "#plan = :planVal",
6 ExpressionAttributeNames: { "#plan": "plan" },
7 ExpressionAttributeValues: { ":planVal": "pro" },
8 Limit: limit,
9}));

Best practices

  • Create a dedicated IAM user with table-specific permissions rather than using broad managed policies like AmazonDynamoDBFullAccess
  • Always use DynamoDBDocumentClient (from @aws-sdk/lib-dynamodb) instead of the base DynamoDBClient to avoid writing manual attribute value marshaling
  • Design your DynamoDB table with access patterns in mind before building — identify partition keys based on the most common query filters
  • Prefer Query over Scan in every UI component — Scan reads all items in the table and is slow and expensive for large datasets
  • Add Global Secondary Indexes for attributes you need to filter by frequently — these allow Query operations on non-key attributes
  • Implement cursor-based pagination using DynamoDB's LastEvaluatedKey and ExclusiveStartKey — DynamoDB does not support offset-based pagination
  • Store the table name in a Cloud Secret rather than hardcoding it in the Edge Function so you can switch between dev and prod tables without code changes
  • Use Conditional expressions (ConditionExpression) on write operations to prevent race conditions — for example, 'attribute_exists(id)' to ensure you're updating an existing item

Alternatives

Frequently asked questions

Can I use DynamoDB Streams to trigger real-time updates in my Lovable app?

DynamoDB Streams notify your backend when items change, but Lovable's Edge Functions are request-response only — they cannot maintain persistent WebSocket connections. To push DynamoDB stream events to your Lovable frontend, you would need an external service (like an AWS Lambda triggered by the DynamoDB Stream) that sends updates via WebSockets or Server-Sent Events to your frontend. Alternatively, poll the DynamoDB table every few seconds using a setInterval in your React component for near-real-time updates.

Does this work with DynamoDB's on-demand pricing mode?

Yes. The on-demand vs provisioned capacity mode is a DynamoDB billing setting that does not affect how your Edge Function calls the API. Whether your table uses on-demand or provisioned throughput, the same AWS SDK v3 commands work identically. On-demand mode is recommended for Lovable apps with unpredictable traffic.

How do I handle DynamoDB's single-table design pattern with this integration?

Single-table design uses a generic partition key (like PK) and sort key (SK) with composite values (like USER#123 and PROFILE#123). Your Edge Function supports this — pass the full composite key values in the partition key and sort key parameters. Ask Lovable to build query helpers that compose these key patterns based on entity type, so your React components can request 'all posts by user 123' without knowing the internal key format.

Can I use AWS IAM roles instead of access keys for better security?

Lovable's Edge Functions run on Supabase's edge infrastructure, not on AWS, so they cannot assume IAM roles through the instance metadata service. Access keys are required for external applications calling the AWS API from outside AWS. Use scoped permissions and rotate keys regularly to minimize risk. If your organization requires role-based access, consider using AWS API Gateway with IAM auth as an intermediary layer.

Why should I use DynamoDB instead of Lovable's built-in Supabase database?

Use Lovable's built-in Supabase if you're starting a new project — you get AI-assisted schema design, automatic RLS policies, and real-time subscriptions for free. Choose DynamoDB only when you already have data in DynamoDB, when your app is deeply integrated into the AWS ecosystem (Lambda, API Gateway, Cognito), or when you specifically need DynamoDB's automatic scaling and single-digit millisecond performance at very high read/write volumes.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.