Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Amazon DynamoDB

Connect Bubble to Amazon DynamoDB via a REST proxy — an AWS Lambda function behind API Gateway, or a Node.js service on Render — that holds your IAM credentials and translates Bubble's HTTPS calls into DynamoDB operations. Bubble cannot call DynamoDB's native API directly because it requires AWS SigV4 cryptographic request signing, which Bubble's API Connector does not support. Your proxy API key lives in a Private header and never reaches the browser.

What you'll learn

  • Why Bubble cannot call DynamoDB directly and why a SigV4-signing proxy is required
  • How to deploy a REST proxy (Lambda + API Gateway or Render Node.js) for DynamoDB
  • How to configure Bubble's API Connector with a Private API key header for the proxy
  • How DynamoDB's key-value model (partition key, sort key) differs from SQL and how to design for it
  • How to handle DynamoDB pagination (LastEvaluatedKey) in Bubble Repeating Groups
  • How DynamoDB Number types are serialized and how the proxy should convert them for Bubble
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced19 min read2 hoursDatabase & BackendLast updated July 2026RapidDev Engineering Team
TL;DR

Connect Bubble to Amazon DynamoDB via a REST proxy — an AWS Lambda function behind API Gateway, or a Node.js service on Render — that holds your IAM credentials and translates Bubble's HTTPS calls into DynamoDB operations. Bubble cannot call DynamoDB's native API directly because it requires AWS SigV4 cryptographic request signing, which Bubble's API Connector does not support. Your proxy API key lives in a Private header and never reaches the browser.

Quick facts about this guide
FactValue
ToolAmazon DynamoDB
CategoryDatabase & Backend
MethodBubble API Connector
DifficultyAdvanced
Time required2 hours
Last updatedJuly 2026

The SigV4 signing requirement: why a proxy is mandatory for Bubble + DynamoDB

Every AWS API call — including DynamoDB — must include an Authorization header containing a cryptographic signature (AWS SigV4). This signature is computed from the request method, URL, headers, body, current timestamp, AWS region, and service name, all hashed with HMAC-SHA256 using your IAM secret key. The signature changes with every request (timestamp-based) and cannot be precomputed or stored.

Bubble's API Connector supports static or dynamic headers but cannot perform HMAC-SHA256 computation at request time. Attempting to call `https://dynamodb.{region}.amazonaws.com` directly from Bubble's API Connector results in 403 Forbidden errors on every single call — there is no workaround within Bubble itself.

The correct architecture places the SigV4 signing inside a proxy service: either an AWS Lambda function (the natural choice since it runs in the same AWS environment as DynamoDB with IAM roles) or a lightweight Node.js service on Render/Railway using the AWS SDK. The proxy accepts simple HTTPS calls from Bubble with a custom API key header, validates the key, and uses the AWS SDK — which handles SigV4 signing automatically — to call DynamoDB.

This is significantly more complex to set up than, for example, connecting Bubble to Upstash Redis (which uses a simple Bearer token). The added complexity is the cost of accessing DynamoDB from outside the AWS ecosystem. Teams considering DynamoDB as their Bubble backend should evaluate whether PostgreSQL via Supabase (simpler setup, similar capabilities for most Bubble apps) might better fit their needs before investing in the proxy infrastructure.

The right use case for Bubble + DynamoDB is teams that already have a DynamoDB-backed system and want to build a Bubble front-end over existing data — not teams starting fresh.

Integration method

Bubble API Connector

Call a custom REST proxy (Lambda + API Gateway or Render Node.js service) from Bubble's API Connector using a Private API key header — the proxy signs AWS SigV4 requests internally.

Prerequisites

  • An AWS account with access to create DynamoDB tables and IAM users (aws.amazon.com)
  • A Render account (render.com) for the Node.js proxy, or familiarity with AWS Lambda + API Gateway
  • A Bubble app on any plan (Free plan works for basic API Connector; paid Bubble plan required for API Workflows / Backend Workflows)
  • The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → search 'API Connector' by Bubble → Install)
  • Basic understanding of key-value database concepts (partition key, sort key)

Step-by-step guide

1

Create a DynamoDB table and IAM credentials

Log into the AWS Console and go to DynamoDB. Click 'Create table'. Choose a table name and, critically, your partition key — the primary attribute DynamoDB uses to distribute and locate items. For example, for a user orders table, the partition key might be `userId` (string). Optionally add a sort key for secondary ordering within a partition — `createdAt` (string in ISO 8601 format) lets you query a user's orders in chronological order. Choose 'On-demand' capacity mode for unpredictable traffic (pay per request), or 'Provisioned' if you know your throughput. On-demand is simpler for Bubble app development. Click 'Create table'. DynamoDB free tier includes 25GB storage and 25 WCU/RCU per month — verify current terms at aws.amazon.com. Next, create an IAM user for proxy credentials: IAM → Users → Create user. Attach an inline policy (or managed policy) granting only the operations your proxy needs: `dynamodb:Query`, `dynamodb:GetItem`, `dynamodb:PutItem`, `dynamodb:UpdateItem`, `dynamodb:DeleteItem` on your specific table ARN. Download the Access Key ID and Secret Access Key — you need these for the proxy environment variables.

dynamodb-iam-policy.json
1// Minimal IAM policy for DynamoDB proxy (least-privilege)
2{
3 "Version": "2012-10-17",
4 "Statement": [
5 {
6 "Effect": "Allow",
7 "Action": [
8 "dynamodb:Query",
9 "dynamodb:GetItem",
10 "dynamodb:PutItem",
11 "dynamodb:UpdateItem",
12 "dynamodb:DeleteItem"
13 ],
14 "Resource": [
15 "arn:aws:dynamodb:{region}:{account-id}:table/{table-name}",
16 "arn:aws:dynamodb:{region}:{account-id}:table/{table-name}/index/*"
17 ]
18 }
19 ]
20}

Pro tip: Design your DynamoDB table schema around your Bubble app's primary access patterns before creating the table. DynamoDB Query requires the partition key — you cannot run arbitrary WHERE filters like SQL without a Global Secondary Index (GSI) or a Scan (slow and expensive). Decide what the most common Bubble query will be and make that the partition key.

Expected result: Your DynamoDB table is created with the correct partition key (and optional sort key). An IAM user has a least-privilege policy granting only the required DynamoDB operations on your specific table. You have the Access Key ID and Secret Access Key saved securely.

2

Deploy a Node.js REST proxy for DynamoDB on Render

Create a new GitHub repository with `package.json` (declaring dependencies on `express` and `@aws-sdk/client-dynamodb` + `@aws-sdk/lib-dynamodb`) and `server.js`. The proxy validates an incoming `X-API-Key` header, then uses the AWS SDK's `DynamoDBDocumentClient` (which handles SigV4 signing and type conversion automatically) to execute DynamoDB operations. Expose three endpoints: `POST /query` (Query by partition key with optional sort key range), `POST /putItem` (insert or replace), `POST /updateItem` (update specific attributes). The Document Client auto-converts DynamoDB's `{"N":"42"}` number type format to plain JavaScript numbers — this is critical for Bubble. Create a Render Web Service, connect your GitHub repo, and set these environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, `TABLE_NAME`, `API_KEY` (a 32-character random secret you generate). Deploy and copy the Render HTTPS URL.

server.js
1// server.js — DynamoDB REST proxy for Bubble
2const express = require('express');
3const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
4const { DynamoDBDocumentClient, QueryCommand, PutCommand, UpdateCommand } = require('@aws-sdk/lib-dynamodb');
5
6const app = express();
7app.use(express.json());
8
9const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({
10 region: process.env.AWS_REGION,
11 credentials: {
12 accessKeyId: process.env.AWS_ACCESS_KEY_ID,
13 secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
14 }
15}));
16
17const TABLE = process.env.TABLE_NAME;
18
19function auth(req, res, next) {
20 if (req.headers['x-api-key'] !== process.env.API_KEY) {
21 return res.status(401).json({ error: 'Unauthorized' });
22 }
23 next();
24}
25
26// Query items by partition key
27app.post('/query', auth, async (req, res) => {
28 const { partitionKey, partitionValue, limit = 25, lastKey } = req.body;
29 const params = {
30 TableName: TABLE,
31 KeyConditionExpression: '#pk = :pkval',
32 ExpressionAttributeNames: { '#pk': partitionKey },
33 ExpressionAttributeValues: { ':pkval': partitionValue },
34 Limit: limit,
35 ...(lastKey && { ExclusiveStartKey: JSON.parse(lastKey) })
36 };
37 const result = await ddb.send(new QueryCommand(params));
38 res.json({
39 items: result.Items || [],
40 lastKey: result.LastEvaluatedKey ? JSON.stringify(result.LastEvaluatedKey) : null
41 });
42});
43
44// Put (insert or replace) an item
45app.post('/putItem', auth, async (req, res) => {
46 const { item } = req.body;
47 await ddb.send(new PutCommand({ TableName: TABLE, Item: item }));
48 res.json({ success: true });
49});
50
51// Update specific attributes
52app.post('/updateItem', auth, async (req, res) => {
53 const { key, updates } = req.body;
54 const expressions = Object.keys(updates).map((k, i) => `#attr${i} = :val${i}`);
55 const names = {};
56 const vals = {};
57 Object.keys(updates).forEach((k, i) => {
58 names[`#attr${i}`] = k;
59 vals[`:val${i}`] = updates[k];
60 });
61 await ddb.send(new UpdateCommand({
62 TableName: TABLE,
63 Key: key,
64 UpdateExpression: `SET ${expressions.join(', ')}`,
65 ExpressionAttributeNames: names,
66 ExpressionAttributeValues: vals
67 }));
68 res.json({ success: true });
69});
70
71app.listen(process.env.PORT || 3000);

Pro tip: Using `DynamoDBDocumentClient` (from `@aws-sdk/lib-dynamodb`) instead of the low-level `DynamoDBClient` is important — it automatically marshals/unmarshals DynamoDB's typed format (`{"N":"42"}` → `42`, `{"S":"hello"}` → `"hello"`). This means Bubble receives clean JSON numbers and strings, not DynamoDB's internal type objects.

Expected result: Your Render proxy is live at a public HTTPS URL. Test a POST to `/query` with your IAM-protected API key header and a valid partition key value — you should receive a JSON response with an `items` array (empty or populated depending on your table data) and a `lastKey` field.

3

Configure Bubble's API Connector with the proxy as a Private API key

In your Bubble editor, go to the Plugins tab. If 'API Connector' by Bubble is not installed, click 'Add plugins', search 'API Connector', and install it. Click 'API Connector', then 'Add another API'. Name it 'DynamoDB Proxy'. In 'Root URL', paste your Render HTTPS URL (e.g., `https://your-dynamodb-proxy.onrender.com`). In 'Shared headers', click 'Add a shared header'. Key: `X-API-Key`. Value: the API key you set in the Render `API_KEY` environment variable. Check the 'Private' checkbox — this is mandatory. The Private checkbox ensures Bubble processes this header on its servers and never sends the API key value to any user's browser. Add a second shared header: Key `Content-Type`, Value `application/json` (leave not private). This is the only correct way to store the proxy API key in Bubble — do not place it in a query parameter or request body where it might appear in browser network logs.

dynamodb-proxy-connector-config.json
1{
2 "root_url": "https://your-dynamodb-proxy.onrender.com",
3 "shared_headers": [
4 {
5 "key": "X-API-Key",
6 "value": "<your-proxy-api-key>",
7 "private": true
8 },
9 {
10 "key": "Content-Type",
11 "value": "application/json",
12 "private": false
13 }
14 ]
15}

Pro tip: If you later need multiple DynamoDB tables in the same Bubble app, create separate API Connector groups (one per table) or add a `tableName` parameter to each proxy endpoint. The latter allows one proxy to serve multiple tables, reducing infrastructure complexity.

Expected result: The 'DynamoDB Proxy' API group appears in your Bubble API Connector with the Render URL set and the X-API-Key header marked Private. You are ready to add individual operation calls.

4

Create the QueryItems call and initialize it for 'Use as Data'

Inside the 'DynamoDB Proxy' API group, click 'Add another call'. Name it 'QueryItems'. Set method to POST, endpoint to `/query`. In the body section, add four parameters: `partitionKey` (text — the name of your partition key attribute, e.g., `userId`), `partitionValue` (text — the value to query, e.g., a dynamic user ID), `limit` (number, default `25`), `lastKey` (text, default `null` for the first page). Click 'Initialize the call'. For initialization, Bubble needs a real successful response — provide a real partition key name and a real value that has items in your DynamoDB table. If your table is empty, insert a test item via the AWS Console first. The response comes back as `{"items":[...], "lastKey":null}`. In the 'Use as Data' dialog, configure Bubble to detect the `items` array as the data type list. Name the detected type something like 'DynamoOrder' or based on your table content. Each DynamoDB attribute becomes a field on this type. The `lastKey` field (a text string) is used for pagination — store it in a custom state for the 'Load More' button.

dynamodb-query-call.json
1// QueryItems — POST body
2{
3 "partitionKey": "userId",
4 "partitionValue": "{{userId}}",
5 "limit": 25,
6 "lastKey": "{{lastKey}}"
7}
8
9// Sample proxy response
10{
11 "items": [
12 {
13 "userId": "user_abc123",
14 "createdAt": "2026-03-15T10:30:00Z",
15 "orderId": "ord_xyz789",
16 "total": 149.99,
17 "status": "shipped"
18 }
19 ],
20 "lastKey": null
21}

Pro tip: DynamoDB's LastEvaluatedKey is a full JSON object (not a simple page number), which your proxy serializes to a string using `JSON.stringify()`. In Bubble, store this string in a custom state. Pass it as the `lastKey` body parameter in the next QueryItems call. The proxy parses it back with `JSON.parse()`. This is DynamoDB's cursor-based pagination — plan it into your Bubble UI early.

Expected result: The QueryItems call initializes successfully. Bubble creates a 'DynamoOrder' data type (or equivalent) with fields matching your DynamoDB item attributes. Numbers come through as numbers (not DynamoDB typed strings) because the Document Client in the proxy handles marshaling automatically. The call is set to 'Use as Data'.

5

Create PutItem and UpdateItem calls

Add a new call named 'PutItem'. Set method to POST, endpoint to `/putItem`. In the body, add one parameter: `item` (object — a representative JSON object matching the structure of a DynamoDB item, including the partition key and all attributes). Set 'Use as' to 'Action'. Initialize with a real test item — confirm it appears in your DynamoDB table via the AWS Console after initialization. Delete test items created during initialization if you do not want them in your production data. Add a second call named 'UpdateItem'. Set method to POST, endpoint to `/updateItem`. Body parameters: `key` (object — contains the partition key and sort key if applicable: `{"userId":"{{userId}}","createdAt":"{{createdAt}}"}`), and `updates` (object — the attributes to update: `{"status":"{{newStatus}}","updatedAt":"{{timestamp}}"}` ). Set 'Use as' to 'Action'. Initialize with a real test item's key and test update values. Note: every DynamoDB update requires the full primary key — partition key plus sort key if your table has one. Store both key attributes in Bubble custom states when a user selects an item to edit.

dynamodb-write-calls.json
1// PutItem body — full item
2{
3 "item": {
4 "userId": "{{userId}}",
5 "createdAt": "{{createdAt}}",
6 "orderId": "{{orderId}}",
7 "total": "{{total}}",
8 "status": "pending"
9 }
10}
11
12// UpdateItem body — key + updates
13{
14 "key": {
15 "userId": "{{userId}}",
16 "createdAt": "{{createdAt}}"
17 },
18 "updates": {
19 "status": "{{newStatus}}",
20 "updatedAt": "{{now}}"
21 }
22}

Pro tip: For RapidDev's AWS-ecosystem clients, architecting the proxy endpoint design is the most critical decision point — especially for complex DynamoDB access patterns with multiple GSIs. If you are building a Bubble front-end over an existing DynamoDB system and need help designing the proxy endpoints to match your table's GSI structure, our team offers free scoping calls at rapidevelopers.com/contact.

Expected result: You have three API Connector calls: QueryItems (Use as Data), PutItem (Action), UpdateItem (Action). Each initializes with a real DynamoDB response. Test each call from the API Connector editor before building Bubble UI on top of them.

6

Build Bubble workflows with DynamoDB pagination using LastEvaluatedKey

Add a Repeating Group to your page. Set data source to 'Get data from external API' → QueryItems. Pass the user's ID (or relevant partition key value) as `partitionValue`, `25` as `limit`, and `null` as `lastKey` for the initial load. Access the 'DynamoOrder' fields on each Repeating Group cell. For pagination, add a 'Load More' button below the Repeating Group. Create a custom state `lastKey` (type: text, default: `null`). When the page loads, store the QueryItems response's `lastKey` field in the `lastKey` custom state (using a 'Set state' workflow action after the initial QueryItems call). The 'Load More' button triggers a new QueryItems call passing the stored `lastKey` as the body parameter. The proxy passes it to DynamoDB as `ExclusiveStartKey`. Append the new items to a Bubble 'custom data list' custom state (type: list of DynamoOrder) that your Repeating Group binds to. Disable the 'Load More' button when `lastKey` custom state is empty (no more pages). For the insert form: PutItem call with each form input mapped to the `item` body object fields. For updates: store the selected item's partition key (and sort key) in custom states when a user clicks edit, then pass them in UpdateItem's `key` parameter. Set up Privacy rules under Data tab → Privacy for any Bubble data types you create from DynamoDB responses.

Pro tip: DynamoDB is not suitable for arbitrary searches across your data. If Bubble users need to search by a non-partition-key attribute (e.g., search orders by product name), you need either a Global Secondary Index (GSI) on that attribute or DynamoDB's Scan operation (expensive). Design your DynamoDB table and proxy endpoints around your top 3 Bubble query patterns before building the app.

Expected result: Your Bubble Repeating Group loads DynamoDB items on page load. The 'Load More' button appends the next page of results using cursor-based pagination. Insert and update workflows write to DynamoDB via the proxy. Pagination correctly handles the cursor (LastEvaluatedKey string) stored in a custom state.

Common use cases

Admin dashboard over existing DynamoDB-backed application

Your existing mobile or web application already stores data in DynamoDB — user records, orders, events. You want to build a Bubble-based admin interface for your operations team to query, update, and delete records without giving them AWS Console access. The proxy exposes your DynamoDB tables as simple REST endpoints. Bubble's Repeating Groups display the data and workflows handle updates.

Bubble Prompt

Build a Bubble admin page that loads the most recent 50 orders from DynamoDB via a REST proxy. Display order ID, user ID, total amount, and status in a Repeating Group. Add a Status dropdown that updates a DynamoDB item when changed. Restrict the page to users with the 'admin' role in Bubble's user database.

Copy this prompt to try it in Bubble

IoT device event log viewer

IoT devices write sensor readings, events, and alerts to a DynamoDB table partitioned by device ID with a timestamp sort key. Bubble becomes the operations dashboard: query by device ID (partition key), filter by time range (sort key), and display the most recent N events per device. The proxy translates Bubble's simple HTTP parameters into DynamoDB Query operations with proper key expressions.

Bubble Prompt

Create a Bubble page where an operator selects a device from a dropdown (populates from a proxy /listDevices endpoint), then sees the last 25 events from that device pulled from DynamoDB via a proxy /query endpoint. Events display in a Repeating Group sorted by timestamp descending. A 'Load more' button passes the LastEvaluatedKey to fetch the next page.

Copy this prompt to try it in Bubble

User activity and audit log append

Your Bubble app needs to write immutable audit log entries to DynamoDB — actions users take, changes to records, security events. DynamoDB's high write throughput and TTL feature (automatically expire old log entries) make it well-suited for append-heavy workloads. The proxy exposes a /putItem endpoint that Bubble calls from workflow steps after any auditable action.

Bubble Prompt

Set up a Bubble workflow step that fires after any form submission and calls the DynamoDB proxy /putItem endpoint to log the action. The log entry includes user ID, action type, affected record ID, timestamp, and the previous and new field values. Use DynamoDB TTL to automatically expire entries older than 90 days.

Copy this prompt to try it in Bubble

Troubleshooting

Bubble API Connector initialize call returns 403 Forbidden when testing

Cause: If you configured the call pointing directly at `dynamodb.amazonaws.com` instead of your proxy, Bubble's API Connector cannot sign AWS SigV4 requests and will always receive 403. If calling the proxy and getting 403, the X-API-Key header does not match the environment variable in Render, or the IAM user's policy does not grant the required DynamoDB operation.

Solution: Confirm your Bubble API Connector root URL points to your Render proxy (e.g., `your-proxy.onrender.com`) — NOT to `amazonaws.com`. If calling the proxy and getting 403, check the Render logs to see what error the proxy returns. Verify the API_KEY environment variable in Render exactly matches the value in Bubble's X-API-Key header. If the proxy returns 'Unauthorized', it's the API key mismatch. If it returns an AWS error, check the IAM policy grants the specific DynamoDB operation on the correct table ARN.

QueryItems returns items with number fields showing as text strings (e.g., total shows as '149.99' not 149.99)

Cause: The proxy is using the low-level DynamoDB client (`DynamoDBClient`) which returns DynamoDB's typed JSON format (`{"N":"149.99"}`), or the Document Client is not properly configured. Bubble maps the outer wrapper as text.

Solution: Ensure your proxy uses `DynamoDBDocumentClient` (from `@aws-sdk/lib-dynamodb`), not the bare `DynamoDBClient`. The Document Client automatically converts DynamoDB typed format to plain JavaScript types. If you cannot change the proxy, add a transformation step in the proxy that maps `{"N":"..."}` to plain numbers before returning the JSON response.

UpdateItem call fails with 'The provided key element does not match the schema'

Cause: The `key` object in the UpdateItem body is missing the sort key (if your table has a sort key), or the partition key attribute name does not match the table's schema exactly (DynamoDB attribute names are case-sensitive).

Solution: Check your DynamoDB table's key schema in the AWS Console — the partition key and sort key names must match exactly what you pass in the `key` object. If your table has a sort key (e.g., `createdAt`), both `userId` AND `createdAt` must be present in the key object. Verify the custom state storing the sort key in Bubble is populated when the user selects an item to edit.

Render proxy cold starts cause Bubble workflow timeouts when users first load the page

Cause: Render's free tier spins down web services after 15 minutes of inactivity. The first request after a period of inactivity triggers a cold start that can take 15-30 seconds — exceeding Bubble's 30-second workflow timeout in some cases.

Solution: Upgrade to a paid Render instance ($7/mo) for always-on service. Alternatively, implement a 'ping' workflow in Bubble that runs on app initialization (every page load) calling a lightweight `/health` endpoint on the proxy — this wakes the proxy before the user triggers a real data call. As a longer-term solution, migrate the proxy to AWS Lambda + API Gateway, which has much faster cold starts and runs in the same AWS environment as DynamoDB.

LastEvaluatedKey pagination stops working after the second page — Load More shows already-seen items

Cause: The `lastKey` custom state is not being updated after each QueryItems call, or the Repeating Group data source is being refreshed from scratch instead of appending new items.

Solution: After each QueryItems call, add a Bubble 'Set state' workflow action to update the `lastKey` custom state with the `lastKey` field from the QueryItems response. Bind the Repeating Group to a separate 'item list' custom state (type: list of DynamoOrder) rather than directly to the QueryItems result. The initial load sets this list state; each 'Load More' click appends to it using Bubble's 'Add to list' option. The QueryItems `lastKey` value drives the next page cursor, not the item list itself.

Best practices

  • Always mark the proxy API key as Private in Bubble's API Connector shared header. The key grants full access to your proxy which then accesses DynamoDB with IAM credentials — never expose it client-side.
  • Use IAM least-privilege: grant the proxy's IAM user only the specific DynamoDB operations it needs (`dynamodb:Query`, `dynamodb:PutItem`, etc.) on the specific table ARN. Never attach `AdministratorAccess` or `AmazonDynamoDBFullAccess` to the proxy user.
  • Design your DynamoDB table schema around your Bubble app's primary access patterns before creating the table. DynamoDB Query requires the partition key — plan which attribute drives each major Bubble list view and make that the partition key or create a GSI for secondary access patterns.
  • Use `DynamoDBDocumentClient` (from `@aws-sdk/lib-dynamodb`) in your proxy, not the bare `DynamoDBClient`. The Document Client auto-converts DynamoDB typed JSON to plain JavaScript types, producing clean JSON that Bubble's 'Use as Data' maps correctly.
  • Set up Privacy rules under Data tab → Privacy in Bubble for any data types created from DynamoDB responses. Without privacy rules, Bubble's built-in search may expose DynamoDB records across user boundaries.
  • Use DynamoDB TTL (Time to Live) for log and audit tables — set an attribute (e.g., `expiresAt` as a Unix timestamp) and enable TTL on it in the DynamoDB table settings. DynamoDB automatically deletes expired items, keeping storage costs low without Bubble needing to run deletion workflows.
  • For Bubble apps with multiple users querying different partitions of DynamoDB data, ensure the partition key in each QueryItems call is always scoped to the current user's ID (or their permitted scope). Never allow a Bubble workflow to query arbitrary partition key values supplied by user input without server-side validation in the proxy.

Alternatives

Frequently asked questions

Why can't I call DynamoDB directly from Bubble's API Connector? Other APIs work fine.

AWS APIs require SigV4 request signing — a cryptographic signature computed from the request body, timestamp, region, and IAM secret key using HMAC-SHA256. This signature is unique to each request (timestamp-based) and cannot be pre-computed or stored as a static header. Bubble's API Connector supports static and dynamic headers but cannot perform HMAC-SHA256 computation at request time. Every call without a valid SigV4 signature returns 403 Forbidden from AWS. The proxy solves this by using the AWS SDK, which handles signing automatically.

Can I use AWS Lambda + API Gateway instead of a Render Node.js service for the proxy?

Yes, and for production AWS-ecosystem Bubble apps it is often the better choice. An AWS Lambda function running the same proxy logic uses an IAM execution role (no static access keys in environment variables) and runs in the same AWS network as DynamoDB, reducing latency. API Gateway provides the HTTPS endpoint. Lambda cold starts are faster than Render's free-tier cold starts, and the pricing (Lambda free tier: 1 million requests/month) is often more cost-effective for moderate-traffic Bubble apps. The proxy code is identical — only the deployment platform changes.

How do I handle DynamoDB's cursor-based pagination (LastEvaluatedKey) in a Bubble Repeating Group?

DynamoDB does not support page numbers. Instead, each query response includes a `LastEvaluatedKey` JSON object pointing to the last item returned. Your proxy serializes this to a string and returns it in the response. In Bubble: (1) create a custom state `lastKey` (type: text); (2) on initial page load, set `lastKey` to the QueryItems response's `lastKey` field; (3) on 'Load More' click, pass the stored `lastKey` string as the body parameter in the next QueryItems call; (4) update `lastKey` with the new response value; (5) disable 'Load More' when `lastKey` is empty (no more pages). Maintain a separate list custom state that accumulates items across pages for the Repeating Group to bind to.

Is DynamoDB free to use with Bubble for development?

DynamoDB's free tier is generous — 25GB storage, 25 write capacity units, and 25 read capacity units per month (verify current terms at aws.amazon.com). For most Bubble development workloads, the free tier is more than sufficient. The Render proxy free tier adds cold-start latency but is free. The main cost to monitor is DynamoDB on-demand mode for unpredictable traffic spikes, and Render paid plan ($7/mo) if cold starts are unacceptable for production. AWS also charges for data transfer out of DynamoDB, which is minimal for typical Bubble app volumes.

Can I search DynamoDB by non-primary-key fields from Bubble?

Not efficiently without planning ahead. DynamoDB Query only accepts the partition key (and optionally sort key) — you cannot run arbitrary `WHERE` filters on other attributes without one of two options: (1) a Global Secondary Index (GSI) on the field you want to filter by — define it when creating the table or add it later; the proxy queries the GSI instead of the main table; or (2) a DynamoDB Scan — reads every item in the table and filters client-side, which is slow and expensive for large tables. Design your GSIs around your Bubble app's search requirements before building.

Do I need a paid Bubble plan to use DynamoDB with Bubble?

No for basic read/write operations via the API Connector — this works on the Free plan. Yes for Bubble API Workflows (Backend Workflows), which are required for server-side scheduled DynamoDB writes, such as a Bubble workflow that runs nightly to archive old DynamoDB items. API Workflows require at minimum the Bubble Starter plan ($32/mo). Most Bubble + DynamoDB integrations involving user-triggered reads and writes work fine on the Free plan.

RapidDev

Talk to an Expert

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

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

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.