Document structure
A DNML request file is a TOML document. It has some keys for the full request, then one block for each operation.
version = "1.0"
name = "reconcile-orders"
description = "Find unpaid orders and flag them."
[variables]
status = "UNPAID"
[defaults]
profileName = "commerce-dev"
region = "ap-southeast-2"
[execution]
onError = "stop"
[[dynamodb.query]]
name = "Find unpaid"
# ...keys of the query
[[dynamodb.update]]
name = "Flag order"
dependsOn = "Find unpaid"
# ...keys of the update Top-Level Keys
| Key | Type | Required | Purpose |
|---|---|---|---|
version | string | Yes | "1.0". See Versioning. |
name | string | Yes | The same as the filename. See Naming rules. |
description | string | No | What the request does. |
variables | table | No | Request variables of any DNML type. |
defaults | table | No | Connection values for all operations. |
execution | table | No | Run options for the full request. |
dynamodb, athena | operation blocks | No | Operation blocks only. |
x | table | No | Extension data. See Unknown keys. |
All keys use camelCase. Do not use the reserved key operations.
Defaults and Execution
[defaults] sets connection values for all operations. An operation that sets the same key uses its own value. Defaults can use templates.
| Key | Applies to |
|---|---|
profileName | All operations. |
region | All operations. |
endpointUrl | All operations. See Endpoints. |
workgroup | Athena operations. |
outputLocation | Athena queries. |
[execution] holds run options for the full request:
| Key | Default | Purpose |
|---|---|---|
onError | "continue" | The default error policy. |
timeoutMs | None | The request deadline, in milliseconds. |
allowDestructive | false | Shows that the request has destructive operations. |
[defaults]
profileName = "${AWS_PROFILE}"
region = "ap-southeast-2"
workgroup = "analytics"
[execution]
onError = "continue"
timeoutMs = 120000 In the app, these keys are in Request settings.
Operation Blocks
Each operation is a [[<namespace>.<operation>]] block. The namespaces are dynamodb and athena.
[[dynamodb.query]]
name = "Find recent order"
tableArn = "arn:aws:dynamodb:ap-southeast-2:111122223333:table/Orders"
keyConditionExpression = "accountId = :accountId"
# Attaches to the most recent [[dynamodb.query]] block
[dynamodb.query.expressionAttributeValues]
":accountId" = "account#42"
[[athena.query]]
name = "Refund report"
region = "ap-southeast-2"
sql = "SELECT * FROM refunds"
[[dynamodb.update]]
name = "Mark reviewed"
dependsOn = "Find recent order"
# ... - The header gives the type. There is no
typekey. An unsupported type causesDNML_UNSUPPORTED_OPERATIONbefore any operation runs. - Blocks keep their file order, also between different types.
- A sub-table, such as
[dynamodb.query.expressionAttributeValues], belongs to the last[[dynamodb.query]]block above it. dependsOncan move a dependency before the operations that need it. See Ordering.
The operation types:
Naming Rules
Request Names
- It must be the same as the filename without
.dnml, and it must not be empty. - It must not contain
/ \ : * ? " < > |or control characters. - It must not start or end with whitespace, or end with
.. - It must not be
collection, in any letter case.
When you rename a request in the app, Dynomate renames the file.
Operation Names
- Each operation must have a unique
name. - Dynomate compares normalized names. A normalized name is lowercase, and each group of whitespace becomes one underscore.
Find recent orderbecomesfind_recent_order. Two equal normalized names causeDNML_DUPLICATE_OPERATION. - Templates read a result by the normalized name. This works only if that name has only lowercase letters, digits and underscores, and no digit at the start.
Variable Names
- It must start with a letter or underscore, then letters, digits or underscores.
- It must not be the same as a normalized operation name. This causes
DNML_ROOT_COLLISION.
Collection Marker
collection.dnml marks a folder as a collection. It has no operation blocks.
# Collection marker (collection.dnml). One of these per collection directory.
version = "1.0"
type = "dynomate-collection"
created = 2026-09-05T00:00:00Z
[metadata]
description = "Order service runbooks"
author = "Platform team"
[metadata.tags]
service = "orders" | Key | Required | Purpose |
|---|---|---|
version | Yes | "1.0". |
type | Yes | Always "dynomate-collection". |
created | Yes | A TOML date-time or an RFC 3339 string. |
metadata.description | No | Free text. |
metadata.author | No | Free text. |
metadata.tags | No | A table of string labels. |
The app writes the marker when you make a collection.
Unknown Keys
A key that DNML does not define causes DNML_UNKNOWN_KEY, at the top level and in operation blocks.
The app opens the request and shows these keys under Unrecognized fields of the request or the operation. Remove them before you save or run the request.
Extensions
Extension keys keep your own data. They never cause errors. Dynomate keeps them when it saves, but does not use them when the request runs:
- Keys that start with
x-, at the top level or in an operation block. - The top-level
[x]table.
version = "1.0"
name = "nightly-cleanup"
x-owner = "platform-team"
[x]
ticket = "OPS-142"
[[dynamodb.scan]]
name = "Find expired sessions"
x-note = "Runs after the TTL sweep"
# ...
An extension cannot add an operation type. [[x.something]] is not an operation block.
Canonical Serialization
Dynomate saves a request in one canonical layout. The same request always gives the same bytes, so a diff shows only real changes.
| Part | Layout |
|---|---|
| File | version, name, description, top-level x- keys, [variables], [defaults], [execution], [x]. Then the operation blocks, with a blank line between them. |
| Block | name, description, dependsOn, enabled, onError, timeoutMs, profileName, region, endpointUrl, tableArn, operation keys, then tags. |
| Free-form maps | Sub-tables with sorted keys, for example variables, item, keyValues and expressionAttributeValues. |
| Small fixed maps | One-line inline tables, for example guard and partitionKey. |
| Lists of maps | One element on each line and a trailing comma, for example puts, keys and actions. |
| Keys without a value | Not written. |
| Strings | Double quotes. SQL and expressions on many lines use '''. |
| Line ends | \n, with one newline at the end of the file. |
[[dynamodb.batchWrite]]
name = "Seed orders"
tableArn = "arn:aws:dynamodb:ap-southeast-2:111122223333:table/Orders"
puts = [
{ accountId = "account#42", orderId = "order-1", status = "NEW" },
{ accountId = "account#42", orderId = "order-2", status = "NEW" },
] You do not have to write this layout. Dynomate reads all valid TOML.
Common Keys
Each operation accepts these keys. The Operation reference gives the other keys.
- name string Required
- The display name of the operation. It must be unique in the request, and other operations use it to refer to the operation. In the app: Rename dialog › Operation name
- description string
- Free-text notes about the operation. In the app: Description and tags dialog › Description
- dependsOn string or string[]
- The names of the operations that must succeed before this operation runs. One name is the same as a list with one name. In the app: Operation header › Add dependency
- enabled boolean
- If false, Dynomate skips the operation and all operations that depend on it. The default is true. In the app: Operation actions menu › Enable / Disable
- onError enum: "stop" | "continue" | "ignore"
- What Dynomate does when the operation fails: "stop" stops the request, "continue" skips only its dependents, and "ignore" lets dependents run without its result. The default is the request setting. In the app: Execution tab › On operation error
- timeoutMs integer
- The maximum time for the operation, in milliseconds. It replaces the default timeout of the operation, but the request timeout still applies. In the app: Execution tab › Operation timeout (ms)
- profileName string
- The AWS profile that Dynomate uses to connect. If you omit it, Dynomate uses the request default, then the profile named "default". In the app: Operation header › AWS profile
- region string
- The AWS region, required for Athena operations, List tables and PartiQL statements. If the operation also has a tableArn, the two regions must match. In the app: Operation header › Region
- endpointUrl string
- A custom endpoint, for example DynamoDB Local. It must use HTTPS, or HTTP on localhost or a loopback address. An endpoint in the file needs confirmation or approval before the request runs. In the app: no field. Dynomate keeps the key when it saves the request.
- tableArn string
- The full ARN of the table, which gives its name and region. All DynamoDB operations except List tables and PartiQL statements require it. In the app: Operation header › Table ARN
name, dependsOn, enabled, onError and timeoutMs cannot use templates.