DynamoDB Conditional Write in Node.js (AWS SDK v3)
A conditional write attaches a ConditionExpression to a PutItem, UpdateItem, or DeleteItem: DynamoDB evaluates it against the current item and applies the write only if it holds — atomically, with no read-modify-write race. It's DynamoDB's optimistic-locking primitive. This example guards an update with a version check.
Code
import {DynamoDBClient, UpdateItemCommand} from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({region: 'us-east-1'});
// Update the item only if nobody changed it since we read version 7.
const command = new UpdateItemCommand({
TableName: 'Music',
Key: {
Artist: {S: 'Arturo Sandoval'},
SongTitle: {S: 'Cubano Chant'}
},
UpdateExpression: 'SET #upd0 = :updValue0, #version = :newVersion',
ConditionExpression: 'attribute_exists(#cond0) AND #version = :expectedVersion',
ExpressionAttributeNames: {
'#upd0': 'Genre',
'#version': 'Version',
'#cond0': 'Artist'
},
ExpressionAttributeValues: {
':updValue0': {S: 'Latin Jazz'},
':expectedVersion': {N: '7'},
':newVersion': {N: '8'}
},
ReturnValuesOnConditionCheckFailure: 'ALL_OLD'
});
try {
await client.send(command);
console.log('Updated to version 8');
} catch (err) {
if (err.name === 'ConditionalCheckFailedException') {
// With ReturnValuesOnConditionCheckFailure: 'ALL_OLD', the current item
// rides back on the exception — no extra read to see what beat you.
console.log('Lost the race — item is now:', err.Item);
} else {
throw err;
}
}Explanation
ConditionExpression— checked against the stored item atomically with the write. Available functions:attribute_exists,attribute_not_exists,attribute_type,contains,begins_with,size, plus comparators (=,<>,<,>,<=,>=,BETWEEN,IN) andAND/OR/NOT.- The two workhorse idioms:
attribute_exists(#key)on an update = "update-only, never create". Without it,UpdateItemon a missing key silently creates the item (the accidental-upsert bug).attribute_not_exists(#key)on a put = "create-only, never overwrite" — shown on the PutItem page.
- Optimistic locking — read the item (version 7), then write with
#version = :expectedVersionwhile bumping to 8. Two concurrent writers can't both win; the loser getsConditionalCheckFailedException, re-reads, and retries on the new version. ReturnValuesOnConditionCheckFailure: 'ALL_OLD'— puts the current item on the exception (err.Item, marshalled), saving the follow-upGetItemafter a failed check. It consumes no read capacity; a failed conditional write still bills its write attempt.- Everything here is aliased (
#version→Version) viaExpressionAttributeNames, so reserved words never bite.
Do it visually
Condition expressions are exactly what the DynamoDB Expression Builder builds — pick the function, get the expression + name/value maps as runnable code.
To edit items with generated, reviewable expressions instead of hand-typed placeholders — download DynoTable.
Related examples
- DynamoDB conditional write in Python — the same optimistic lock with boto3.
- DynamoDB conditional write with the AWS CLI — the same optimistic lock from the shell.
- DynamoDB PutItem in Node.js — the create-only
attribute_not_existsput. - DynamoDB condition expressions — every function, with patterns.
- Enforcing uniqueness on multiple attributes — conditions + transactions combined.
- DynamoDB ConditionalCheckFailedException — when the failed check is expected, and how to handle it cheaply.
References
- UpdateItem — Amazon DynamoDB API Reference
- Condition expressions — Amazon DynamoDB Developer Guide
- DynamoDB read and write operations (capacity unit consumption) — Amazon DynamoDB Developer Guide
Last verified 2026-07-13 against the official AWS documentation linked above.