# How to Integrate Retool with Amazon DynamoDB

- Tool: Retool
- Difficulty: Intermediate
- Time required: 15 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to Amazon DynamoDB using Retool's native DynamoDB connector. In the Resources tab, add a DynamoDB resource, provide AWS IAM credentials and region, then run Query and Scan operations directly from Retool's query editor. Build admin panels to browse DynamoDB tables, query items by partition and sort key, update records, and visualize NoSQL data without writing any backend code.

## Why Connect Retool to Amazon DynamoDB?

DynamoDB powers the backend of countless AWS-hosted applications, but it lacks a native management UI beyond the basic AWS Console. Engineering teams spend significant time writing one-off Lambda functions or scripts to inspect data, fix records, run ad-hoc queries, and manage operational incidents. Retool's DynamoDB connector lets you build purpose-built admin panels that wrap these operations in a polished UI accessible to the entire team without AWS console access.

The core challenge with DynamoDB in any admin tool is its NoSQL data model: unlike SQL databases, DynamoDB requires knowledge of partition keys, sort keys, and Global Secondary Indexes (GSIs) to retrieve data efficiently. Retool's DynamoDB query editor surfaces these concepts directly — you specify the table name, key condition expression, and filter expression in a structured form, avoiding the need to write raw DynamoDB API calls. For broad data exploration, Scan operations with filter expressions let you retrieve records based on any attribute, though at higher cost for large tables.

Typical use cases include operational dashboards for inspecting DynamoDB records during incident response, admin panels for customer support teams to look up user records by customer ID, data correction tools that allow engineers to update DynamoDB items without writing code, and reporting dashboards that aggregate DynamoDB data via Scan operations combined with JavaScript transformers for in-memory aggregation.

## Before you start

- An AWS account with at least one DynamoDB table
- An IAM user or role with permissions: dynamodb:Query, dynamodb:Scan, dynamodb:GetItem, dynamodb:PutItem, dynamodb:UpdateItem, dynamodb:DeleteItem, dynamodb:DescribeTable, dynamodb:ListTables
- AWS Access Key ID and Secret Access Key for the IAM user (or IAM role ARN for role assumption)
- Knowledge of your DynamoDB table's partition key name, sort key name (if applicable), and any Global Secondary Index names
- A Retool account (Cloud or self-hosted) with permission to create Resources

## Step-by-step guide

### 1. Configure IAM permissions and create AWS credentials for Retool

In the AWS Console, navigate to IAM → Users → Create User. Create a dedicated IAM user named retool-dynamodb with access type 'Programmatic access' (Access Key). Rather than granting AdministratorAccess or DatabaseAdministrator, attach a custom inline policy granting only the DynamoDB actions Retool needs.

The minimum policy requires read and write operations on your specific DynamoDB tables. Restrict the Resource field to the specific table ARNs and their indexes rather than using wildcards — for example, arn:aws:dynamodb:us-east-1:123456789:table/customers and arn:aws:dynamodb:us-east-1:123456789:table/customers/index/* for all indexes on that table.

After creating the user, go to the Security Credentials tab and create an Access Key. Select 'Application running outside AWS'. Copy the Access Key ID and Secret Access Key. The secret is shown only once — store it in a password manager immediately.

For self-hosted Retool running on EC2 or ECS: attach an IAM role to the compute instance with the DynamoDB policy. In the Retool DynamoDB resource, select 'AWS IAM Role' authentication and provide the role ARN instead of access keys. This is the more secure pattern because credentials rotate automatically.

For Retool Cloud: you must use access key authentication (role assumption requires self-hosted Retool running in the same AWS account). Retool Cloud proxies all DynamoDB requests through its servers, so your DynamoDB table does not need to be publicly accessible — AWS IAM authentication handles authorization at the API level.

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:ListTables"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem",
        "dynamodb:DeleteItem",
        "dynamodb:DescribeTable",
        "dynamodb:BatchWriteItem",
        "dynamodb:BatchGetItem"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_ID:table/your-table-name",
        "arn:aws:dynamodb:us-east-1:YOUR_ACCOUNT_ID:table/your-table-name/index/*"
      ]
    }
  ]
}
```

**Expected result:** An IAM user with a programmatic access key exists with the DynamoDB policy attached. You have the Access Key ID and Secret Access Key ready for Retool resource configuration.

### 2. Add the Amazon DynamoDB Resource in Retool

Open your Retool instance and navigate to the Resources tab in the left sidebar. Click Add Resource. In the resource type list, find 'Amazon DynamoDB' under the Database category or search for 'DynamoDB'.

Enter a descriptive name for the resource: 'DynamoDB Production us-east-1' or 'Customer Data DynamoDB' works well. In the Authentication section, select 'AWS Access Key'. Enter the Access Key ID and Secret Access Key from the IAM user you created. In the Region dropdown, select the AWS region where your DynamoDB tables reside — this is critical and must match exactly.

For role-based authentication on self-hosted Retool: select 'AWS IAM Role' and enter the role ARN (arn:aws:iam::ACCOUNT_ID:role/RoleName). If Retool is running on EC2/ECS with an instance profile, select 'Use Instance Role' and no credentials are needed.

Click Save Changes. Retool tests the connection by attempting to call the DynamoDB ListTables API. A green success message confirms the connection. If you see an error, double-check the region setting — mismatched region is the most common cause of DynamoDB connection failures.

Note: unlike Retool's database resources (PostgreSQL, MySQL), DynamoDB does not require a host, port, or connection string. Authentication is entirely through AWS IAM, and the DynamoDB endpoint is automatically determined from the configured AWS region.

**Expected result:** The DynamoDB resource appears in your Resources list with a green Connected status. You can now create DynamoDB queries in any Retool app using this resource.

### 3. Run Query and Scan operations in the Retool query editor

Open a Retool app and create a new query. Select your DynamoDB resource. The DynamoDB query editor shows a Table Name field and an Action dropdown with the available DynamoDB operations: Query, Scan, GetItem, PutItem, UpdateItem, DeleteItem, DescribeTable, and ListTables.

Understanding the difference between Query and Scan is essential for DynamoDB performance:
- Query: retrieves items using the partition key (required) and optionally the sort key. Fast and efficient — reads only the items that match the key. Use this for customer lookups, order history, and any access pattern aligned with your table's key schema.
- Scan: reads every item in the table and applies a filter. Expensive for large tables (reads and charges all items even if only a few match). Use for admin exploration and small tables — never for high-frequency production queries.

For a Query operation: set Action to Query, enter the Table Name. In the Key Condition Expression field, enter the condition using DynamoDB expression syntax: customer_id = :pk. In the Expression Attribute Values section, define the value for :pk using {{ }} to reference a Retool component: { ":pk": { "S": "{{ customerIdInput.value }}" } }. Note that DynamoDB requires explicit type definitions — { "S": value } for strings, { "N": "123" } for numbers (as strings), { "BOOL": true } for booleans.

For a Scan with filter: set Action to Scan. In the Filter Expression field, enter status = :status AND created_at > :since. In Expression Attribute Values, define each placeholder.

Create a JavaScript transformer to flatten and format the DynamoDB response. DynamoDB wraps every attribute value in a type descriptor, so { customer_id: { S: 'abc123' }, amount: { N: '99.99' } } needs to be unwrapped into { customer_id: 'abc123', amount: 99.99 } for display in Retool tables.

```
// DynamoDB response transformer — unwrap DynamoDB type descriptors
// Input: data (array of raw DynamoDB items from Query or Scan)

const items = data || [];

// Helper function to unwrap DynamoDB typed values
function unwrapDynamoDBValue(val) {
  if (val.S !== undefined) return val.S;
  if (val.N !== undefined) return parseFloat(val.N);
  if (val.BOOL !== undefined) return val.BOOL;
  if (val.NULL !== undefined) return null;
  if (val.L !== undefined) return val.L.map(unwrapDynamoDBValue);
  if (val.M !== undefined) {
    return Object.entries(val.M).reduce((obj, [k, v]) => {
      obj[k] = unwrapDynamoDBValue(v);
      return obj;
    }, {});
  }
  if (val.SS !== undefined) return val.SS;
  if (val.NS !== undefined) return val.NS.map(parseFloat);
  return val;
}

return items.map(item =>
  Object.entries(item).reduce((obj, [key, value]) => {
    obj[key] = unwrapDynamoDBValue(value);
    return obj;
  }, {})
);
```

**Expected result:** The Query or Scan operation returns DynamoDB items. The transformer unwraps DynamoDB's type descriptors into plain JavaScript objects that display cleanly in a Retool Table component with readable values instead of { S: 'value' } notation.

### 4. Implement CRUD operations: Update and create DynamoDB items

DynamoDB's write operations in Retool use the PutItem, UpdateItem, and DeleteItem actions. Understanding when to use each is important:
- PutItem: creates a new item or completely replaces an existing item with the same primary key. Use for creating new records.
- UpdateItem: modifies specific attributes of an existing item without replacing the whole item. Use for targeted updates.
- DeleteItem: removes an item by its primary key.

For an Update operation: create a query named updateItem. Set Action to UpdateItem. Set Table Name and the partition key value: { "customer_id": { "S": "{{ table1.selectedRow.data.customer_id }}" } }. For tables with a sort key, include it here too. In the Update Expression field, enter: SET status = :newStatus, updated_at = :now. In Expression Attribute Values: { ":newStatus": { "S": "{{ statusSelect.value }}" }, ":now": { "S": "{{ new Date().toISOString() }}" } }.

For creating a new item: set Action to PutItem. In the Item field, provide the full item as a typed JSON object. Reference form component values for each attribute.

For conditional updates (updating only if the item hasn't been modified by another process): add a Condition Expression such as attribute_exists(customer_id) AND version = :expectedVersion. DynamoDB returns a ConditionalCheckFailedException if the condition fails, which you can catch in Retool's error handlers.

Chain write operations with data refresh: in each write query's Event Handlers section, add an On Success handler that triggers your listData query to refresh the table. Add an On Failure handler to show a notification with the error message using {{ queryName.error.message }}.

```
// UpdateItem query configuration
// Action: UpdateItem
// Table Name: customers
// Key:
{
  "customer_id": { "S": "{{ table1.selectedRow.data.customer_id }}" }
}

// Update Expression:
// SET #status = :newStatus, updated_at = :now, notes = :notes

// Expression Attribute Names (for reserved words like 'status'):
{
  "#status": "status"
}

// Expression Attribute Values:
{
  ":newStatus": { "S": "{{ statusDropdown.value }}" },
  ":now": { "S": "{{ new Date().toISOString() }}" },
  ":notes": { "S": "{{ notesInput.value }}" }
}

// Condition Expression (optional — ensure item exists):
// attribute_exists(customer_id)
```

**Expected result:** Clicking Update in the Retool app writes the changed attributes to DynamoDB via UpdateItem. The table refreshes to show the updated values. PutItem creates new records visible in the DynamoDB Console and in subsequent Retool queries.

### 5. Handle pagination, GSIs, and advanced query patterns

DynamoDB Query and Scan operations return a maximum of 1 MB of data per request. For tables with large items or many results, Retool's DynamoDB connector returns a LastEvaluatedKey in the response when more items are available. Implement pagination by storing this key and passing it as ExclusiveStartKey in subsequent queries.

For Global Secondary Indexes (GSIs): in the Query action, set the Index Name field to your GSI name (e.g., status-created_at-index). The Key Condition Expression must reference the GSI's partition key, not the table's partition key. For example, if your GSI has status as its partition key, use status = :s instead of customer_id = :id.

For begins_with queries on sort keys (common for time-range filtering with ISO date prefixes): use the sort key condition BETWEEN :start AND :end or begins_with(created_at, :prefix) in the Key Condition Expression.

For complex admin exploration where you need to inspect all items in a table: build a Scan-based explorer with configurable filter expressions. Use a TextInput component for the Filter Expression, another for Expression Attribute Values (as a JSON string parsed with JSON.parse({{ filterValuesInput.value }})), and bind results to a Table. This gives engineers a direct DynamoDB query interface from within Retool.

For complex multi-table DynamoDB dashboards with batch operations, Retool Workflows, and sophisticated data transformation pipelines, RapidDev's team can help architect and build your complete Retool solution.

```
// GSI Query configuration example
// Table: orders
// Index Name: status-created_at-index
// Action: Query
// Key Condition Expression:
// #status = :s AND created_at BETWEEN :start AND :end

// Expression Attribute Names:
{
  "#status": "status"
}

// Expression Attribute Values:
{
  ":s": { "S": "{{ statusFilter.value }}" },
  ":start": { "S": "{{ moment(dateRange.startDate).toISOString() }}" },
  ":end": { "S": "{{ moment(dateRange.endDate).endOf('day').toISOString() }}" }
}

// Scan Limit: 100
// Filter Expression (additional non-key filter):
// amount > :minAmount
// Expression Attribute Values (add to above):
// ":minAmount": { "N": "{{ minAmountInput.value || '0' }}" }
```

**Expected result:** GSI queries return results based on the non-primary key index. Paginated results are navigable via the stored LastEvaluatedKey. Complex filter expressions work correctly when reserved word conflicts are resolved with Expression Attribute Names.

## Best practices

- Always use Query over Scan when you know the partition key — Query is dramatically faster, cheaper, and does not impact table performance for other users in the same way that a full-table Scan does.
- Design your admin tool access patterns before building your Retool app — know which partition keys, sort keys, and GSIs exist so you can write efficient Query operations rather than relying on expensive Scan operations.
- Use Expression Attribute Names (the #alias pattern) for any DynamoDB attribute that conflicts with reserved words like status, name, type, date, time, and timestamp to avoid expression parse errors.
- Create a dedicated IAM user with DynamoDB permissions scoped to specific table ARNs rather than granting dynamodb:* on all resources, following the principle of least privilege.
- Add a transformer to every DynamoDB query to unwrap DynamoDB's type descriptor format into plain JavaScript values before binding results to Retool Table and Form components.
- Implement pagination awareness in your Retool app: check for LastEvaluatedKey in query responses and provide a 'Load More' button for large result sets rather than attempting to retrieve all items in a single request.
- For write-heavy admin operations, use Retool's GUI query mode and add confirmation dialogs before executing DynamoDB DeleteItem or PutItem (which replaces the entire item) operations on production tables.

## Use cases

### Build a customer record lookup panel using partition key queries

Create a Retool app where support engineers can enter a customer ID to instantly retrieve that customer's DynamoDB record. Use a Query operation with the customer_id partition key to fetch the exact item without a full table scan. Display the result in a JSON viewer or structured form, and add an Edit button that opens a modal for updating specific fields.

Prompt example:

```
Build a customer lookup panel with a text input for Customer ID. When submitted, run a DynamoDB Query operation on the 'customers' table with KeyConditionExpression 'customer_id = :id' and show the result in a formatted table. Include an Edit button that opens a modal showing all attributes as editable fields, and a Save button that runs UpdateItem to write changes back to DynamoDB.
```

### Create an order management dashboard with GSI queries

Build a dashboard that queries a DynamoDB orders table using a Global Secondary Index on the status attribute. Display orders filtered by status (pending, processing, shipped, delivered) in a Table component. Allow support staff to update order status from the UI and view order history for a specific customer by querying the customer_id partition key.

Prompt example:

```
Build an order management dashboard that queries the 'orders' DynamoDB table on the 'status-index' GSI filtered by order status. Show a table with order_id, customer_id, status, total_amount, and created_at. Add filter dropdowns for status and a date range for created_at. Include an Update Status action that runs UpdateItem to change an order's status.
```

### Build a DynamoDB table explorer for engineering teams

Create an internal tool that lists all DynamoDB tables in the AWS account, allows selecting a table, describes its schema (key schema, GSIs, billing mode), and runs a configurable Scan or Query operation. Display results in a Table with JSON column rendering for nested attributes. Include a raw JSON view for inspecting the full item structure.

Prompt example:

```
Build a DynamoDB explorer with a dropdown populated by ListTables showing all available tables. When a table is selected, show its key schema, GSIs, item count, and table size from DescribeTable. Below that, show a Scan operation on the table (up to 100 items) with a JSON filter expression input, and display results in a table where nested attributes are shown as formatted JSON strings.
```

## Troubleshooting

### Query returns 'ValidationException: The table does not exist' or 'ResourceNotFoundException'

Cause: The table name in the query is misspelled, uses the wrong case (DynamoDB table names are case-sensitive), or the configured AWS region does not match the region where the table resides.

Solution: Verify the exact table name in the AWS DynamoDB Console in the correct region. DynamoDB table names are case-sensitive: 'Customers' and 'customers' are different tables. In the Retool DynamoDB resource settings, confirm the Region matches where your table was created. If you have tables in multiple regions, create a separate Retool resource for each region.

### 'ValidationException: Value provided in ExpressionAttributeValues unused in expressions' error

Cause: An ExpressionAttributeValues entry is defined but not referenced in any expression (KeyConditionExpression, FilterExpression, or ConditionExpression). DynamoDB throws a validation error when expression attribute values are defined but not used.

Solution: Check that every key in your ExpressionAttributeValues (e.g., :status, :start) appears at least once in one of your expression fields. Remove any unused placeholders. This error commonly occurs when switching between operation types and not cleaning up leftover expression values from a previous configuration.

### Data appears in raw DynamoDB format ({ S: 'value', N: '123' }) instead of readable values in the Table component

Cause: DynamoDB returns all attribute values wrapped in type descriptors ({ S: 'string' }, { N: 'number' }, { BOOL: true }) rather than plain JavaScript values. Without a transformer, these objects display as [object Object] or JSON strings in Retool tables.

Solution: Add a JavaScript transformer to the DynamoDB query (Advanced tab → Add Transformer) that unwraps the DynamoDB type descriptors into plain values. Use the unwrapDynamoDBValue transformer provided in Step 3 of this guide. Apply it to all items in the response array.

```
// Add to query's transformer
const items = data || [];
function unwrap(v) {
  if (v.S !== undefined) return v.S;
  if (v.N !== undefined) return parseFloat(v.N);
  if (v.BOOL !== undefined) return v.BOOL;
  if (v.NULL !== undefined) return null;
  if (v.L) return v.L.map(unwrap);
  if (v.M) return Object.entries(v.M).reduce((o,[k,val]) => ({...o,[k]:unwrap(val)}),{});
  return v;
}
return items.map(item => Object.entries(item).reduce((o,[k,v]) => ({...o,[k]:unwrap(v)}),{}));
```

### 'AccessDeniedException: User is not authorized to perform dynamodb:Query on resource' error

Cause: The IAM user or role used by Retool does not have the required DynamoDB permission for the operation, or the policy resource ARN does not include the specific table or GSI being queried.

Solution: In the AWS IAM Console, review the policy attached to the Retool IAM user. Ensure the action (dynamodb:Query, dynamodb:Scan, etc.) is explicitly allowed. For GSI queries, the resource ARN must include the index path: arn:aws:dynamodb:REGION:ACCOUNT:table/TABLE_NAME/index/* — a policy granting access only to the table ARN does not automatically cover indexes.

## Frequently asked questions

### Can Retool query DynamoDB without a partition key using Scan?

Yes. The Scan operation in Retool's DynamoDB query editor reads all items in a table and applies optional filter expressions. However, Scan reads every item in the table regardless of the filter — this consumes read capacity proportional to the table size and is expensive for large tables. Use Scan for admin tools and small tables only. For tables with millions of items, design your Retool queries around Query operations using partition keys or GSIs.

### Does Retool support DynamoDB Streams or real-time data updates?

Retool does not natively subscribe to DynamoDB Streams. For real-time updates in a Retool dashboard, configure the query to auto-run on a polling interval (set in the query's Advanced settings). DynamoDB Streams-based automation (reacting to item changes) is better handled in Retool Workflows with webhook triggers, where a Lambda function processes the DynamoDB Stream and calls a Retool Workflow webhook when relevant changes occur.

### How do I query DynamoDB Global Secondary Indexes (GSIs) in Retool?

In the Query action within Retool's DynamoDB query editor, there is an Index Name field. Enter the exact GSI name as defined in DynamoDB. Then write your Key Condition Expression using the GSI's partition key (not the table's partition key). For example, if your table's primary key is customer_id but you have a GSI named status-index with partition key status, your Key Condition Expression in Retool would be #status = :s with Expression Attribute Names mapping #status to status.

### Can Retool access DynamoDB tables in multiple AWS regions?

Yes, but you need a separate Retool resource for each region. DynamoDB is a regional service and each Retool resource is configured for a specific AWS region. Create a DynamoDB resource for us-east-1, another for eu-west-1, and so on. Individual Retool apps can query multiple DynamoDB resources — for example, a global admin panel might query the us-east-1 resource and the eu-west-1 resource in parallel, combining results via a JavaScript transformer.

### What is the maximum number of items Retool can retrieve from a DynamoDB query?

A single DynamoDB Query or Scan operation returns up to 1 MB of data. Retool's connector implements automatic pagination — you can use the Limit parameter to control items per page and the LastEvaluatedKey from the response to fetch subsequent pages. For very large datasets, implement pagination in your Retool app using a state variable to track the current page key, or use Retool Workflows for batch data export operations.

---

Source: https://www.rapidevelopers.com/retool-integrations/amazon-dynamodb
© RapidDev — https://www.rapidevelopers.com/retool-integrations/amazon-dynamodb
