Automation and CI
Use dynomate-cli requests run in scripts and CI jobs. Ask for JSON, check the exit code, and approve the request in advance with --approval never.
First, install the CLI on the runner.
JSON output
--format json prints one JSON document to standard output, also when the request fails. This is the running example with endpointUrl = "http://localhost:8000", against DynamoDB Local:
{ "version": "1.0", "request": "find-and-update-order", "status": "success", "startedAt": "2026-09-23T06:45:48.976Z", "finishedAt": "2026-09-23T06:45:49.456Z", "error": null, "outcomes": [ { "name": "Find recent order", "type": "dynamodb.query", "status": "success", "startedAt": "2026-09-23T06:45:48.978Z", "durationMs": 456, "destructive": false, "endpoint": "http://localhost:8000", "endpointUses": [ { "operationName": "Find recent order", "operationKind": "dynamodb.query", "role": "operation", "service": "dynamodb", "profile": "commerce-dev", "region": "ap-southeast-2", "endpoint": "http://localhost:8000", "source": "documentOverride" } ], "result": { "count": 1, "items": [ { "accountId": "account#42", "orderId": "order#9812", "status": "PENDING", "total": 42 } ], "lastEvaluatedKey": "eyJvcmRlcklkIjp7IlMiOiJvcmRlciM5ODEyIn0sImFjY291bnRJZCI6eyJTIjoiYWNjb3VudCM0MiJ9fQ==", "pages": 1, "requestId": "280d3dd1-c3f2-4cd0-94cd-6ed02fa5d258", "scannedCount": 1 } }, { "name": "Mark reviewed", "type": "dynamodb.update", "status": "success", "startedAt": "2026-09-23T06:45:49.435Z", "durationMs": 9, "destructive": true, "endpoint": "http://localhost:8000", "endpointUses": [ { "operationName": "Mark reviewed", "operationKind": "dynamodb.update", "role": "operation", "service": "dynamodb", "profile": "commerce-dev", "region": "ap-southeast-2", "endpoint": "http://localhost:8000", "source": "documentOverride" } ], "result": { "attributes": { "accountId": "account#42", "orderId": "order#9812", "status": "REVIEWED", "total": 42 }, "requestId": "4a75c4cf-47a1-4115-a8d1-85242d4cf39f" } }, { "name": "Read back", "type": "dynamodb.get", "status": "success", "startedAt": "2026-09-23T06:45:49.444Z", "durationMs": 11, "destructive": false, "endpoint": "http://localhost:8000", "endpointUses": [ { "operationName": "Read back", "operationKind": "dynamodb.get", "role": "operation", "service": "dynamodb", "profile": "commerce-dev", "region": "ap-southeast-2", "endpoint": "http://localhost:8000", "source": "documentOverride" } ], "result": { "found": true, "item": { "accountId": "account#42", "orderId": "order#9812", "status": "REVIEWED", "total": 42 }, "requestId": "1ebbbe86-9637-4e7f-8fe2-f0048f0609c4" } } ]} | Field | Description |
|---|---|
version | The DNML version of the request: "1.0", or "1.1" for a request with an Amazon Aurora DSQL operation. |
request | The request name. |
status | success, partial or failed. |
startedAt, finishedAt | UTC times of the run. |
error | A request-level error, for example from validation, or null. |
outcomes | One outcome for each operation, in run order. It is empty if the run did not start. |
Each outcome has the name, type and status of the operation, and a result, error or skipReason. An operation that started also has startedAt and durationMs. It can also have destructive, endpoint and endpointUses. Aurora DSQL outcomes have no endpoint or endpointUses.
The Operation reference shows the result of each operation type.
Parse the result
Read the JSON with a tool such as jq:
# Overall status: success, partial or failedjq -r '.status' result.json# One line per operation, with the skip reason when there is onejq -r '.outcomes[] | "\(.name): \(.status) \(.skipReason // "")"' result.json# Error code of the request, or of every failed operationjq -r '.error.code // empty, (.outcomes[] | .error.code // empty)' result.json# A value from one operation's resultjq -r '.outcomes[] | select(.name == "Read back") | .result.item.status' result.json Standard output contains only the result, so you can parse it safely.
Exit codes in CI
Use the exit code to pass or fail a CI step:
0: the request succeeded.1: the status ispartialorfailed.2: the command line is not valid. Do not parse the empty output.
This step prints each operation status and keeps the exit code:
#!/usr/bin/env bashset -uo pipefaildynomate-cli requests run ./orders/find-and-update-order.dnml \ --approval never \ --format json > result.jsoncode=$?if [ "$code" -eq 2 ]; then echo "dynomate-cli was called with invalid arguments" >&2 exit 2fijq -r '.outcomes[] | "\(.name): \(.status)"' result.jsonexit "$code" Approval in automation
A CI job has no terminal. A request that needs approval fails with APPROVAL_FAILED and exit code 1.
With the default --approval auto, a request with dynamodb.deleteTable, dynamodb.truncate or an endpointUrl needs approval. Aurora DSQL operations do not need approval.
To run the request, use --approval never. Do not use --approval always in automation, because each run needs a terminal.
Pass inputs and secrets
Templates cannot read environment variables, so give each value with --input:
- Do not declare these names in
[variables], because request variables override inputs. - A missing input fails the request before any operation runs.
- The CLI does read
DYNO_APP_DATA_DIRand the AWS credential variables.
DynamoDB Local in CI
To test in CI with no AWS credentials:
-
Start DynamoDB Local with
-sharedDb:docker run -d -p 8000:8000 amazon/dynamodb-local -jar DynamoDBLocal.jar -sharedDb -inMemory -
Set
endpointUrlin[defaults]or on an operation:DNML[defaults]profileName = "commerce-dev"endpointUrl = "http://localhost:8000" - Create the tables and add seed data.
- Run the request with
--approval never.
- Without
-sharedDb, DynamoDB Local keeps separate data for each access key and region. Dynomate uses its own placeholder keys, so the request cannot see tables from other tools. - Dynomate accepts plain HTTP only for
localhost, IPv4 loopback addresses such as127.0.0.1, and::1. - For
localhost,127.0.0.1and::1, Dynomate does not use the AWS credentials of the profile. - With
-sharedDb, you do not change the table ARNs in the request.
To add seed data with table import, use a profile with the local endpoint_url and placeholder keys.
For a GitHub Actions example, see DynamoDB Local in CI/CD pipelines.