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) and AND/OR/NOT.
  • The two workhorse idioms:
    • attribute_exists(#key) on an update = "update-only, never create". Without it, UpdateItem on 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 = :expectedVersion while bumping to 8. Two concurrent writers can't both win; the loser gets ConditionalCheckFailedException, re-reads, and retries on the new version.
  • ReturnValuesOnConditionCheckFailure: 'ALL_OLD' — puts the current item on the exception (err.Item, marshalled), saving the follow-up GetItem after a failed check. It consumes no read capacity; a failed conditional write still bills its write attempt.
  • Everything here is aliased (#versionVersion) via ExpressionAttributeNames, 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.

References

Last verified 2026-07-13 against the official AWS documentation linked above.

Work with DynamoDB without the Console

DynoTable is a fast desktop client for DynamoDB — browse tables, run SQL-style queries, and edit items locally.