Beginner7 min read

How to Delete Multiple Items in DynamoDB

There is no DELETE FROM table WHERE … in DynamoDB. Every delete targets one item by its full primary key — the API has no bulk-delete operation, no truncate, and 's DELETE statement removes exactly one item per statement. So "delete multiple items" is always a two-step job: find the keys, then issue one delete per key, batched for throughput.

This guide covers the batching options, the all-or-nothing transactional variant, the delete-everything case, and how to do the same thing with a selection and two keystrokes in a GUI.

How do I delete multiple items in DynamoDB?

Collect the primary keys of the items you want gone (via Query or Scan), then delete them in batches: BatchWriteItem takes up to 25 DeleteRequests per call, TransactWriteItems deletes up to 100 items atomically, and PartiQL DELETE statements can be batched 25 at a time with BatchExecuteStatement. In DynoTable you select the rows and press ⌘⌫ to stage the deletes, then review and commit.

Step 0: collect the keys

A delete needs the entire primary key — on a table that's the partition key and the sort key (AWS: "For each primary key, you must provide all of the key attributes"). You can't delete by an arbitrary attribute, so "delete every item where status = 'archived'" starts with a read:

  • If the condition lives on a key (or a GSI key), a targeted Query collects the keys cheaply.
  • Otherwise it's a Scan with a filter — which reads (and bills) the whole table, filter or not; see query vs scan.

Use a ProjectionExpression that returns only the key attributes, and follow LastEvaluatedKey to the end (pagination) or you'll silently delete only the first 1 MB page's worth.

Method 1: BatchWriteItem (up to 25 deletes per call)

BatchWriteItem bundles up to 25 put/delete requests or 16 MB per call (AWS API reference: "A single call to BatchWriteItem can transmit up to 16MB of data over the network, consisting of up to 25 item put or delete operations").

aws dynamodb batch-write-item --request-items '{
  "Orders": [
    {"DeleteRequest": {"Key": {"PK": {"S": "ORDER#1001"}, "SK": {"S": "META"}}}},
    {"DeleteRequest": {"Key": {"PK": {"S": "ORDER#1002"}, "SK": {"S": "META"}}}},
    {"DeleteRequest": {"Key": {"PK": {"S": "ORDER#1003"}, "SK": {"S": "META"}}}}
  ]
}'

Three properties of the batch trip people up — all straight from the API reference:

  • It's not atomic. "The individual PutItem and DeleteItem operations specified in BatchWriteItem are atomic; however BatchWriteItem as a whole is not." Some deletes can land while others don't.
  • You must retry UnprocessedItems. Throttled requests come back in the UnprocessedItems response map, in the same shape as the request — "Typically, you would call BatchWriteItem in a loop", and AWS "strongly recommend[s] that you use an exponential backoff algorithm" between retries.
  • No conditions. "You cannot specify conditions on individual put and delete requests" — a conditional delete has to go through DeleteItem or a transaction instead. A batch also rejects two operations on the same key in one call.

The loop shape — chunk by 25, send, re-queue the leftovers with backoff — is the same one covered in batch operations.

Method 2: TransactWriteItems (atomic deletes)

When a set of deletes must succeed or fail together — removing a parent item and its children, say — use TransactWriteItems: up to 100 actions (deletes, puts, updates, condition checks) applied atomically, with per-item allowed. The trade: a transactional write costs double the write capacity of a plain write. The full mechanics (idempotency tokens, TransactionCanceledException, cost math) are in DynamoDB transactions.

Method 3: PartiQL DELETE, batched

PartiQL doesn't lift the per-key rule — it just respells it. The developer guide is explicit (PartiQL DELETE): "You can only delete one item at a time. You cannot issue a single DynamoDB PartiQL statement that deletes multiple items", and the WHERE condition "must resolve to a single primary key value".

To delete several items you batch single-item statements — BatchExecuteStatement runs up to 25 statements per batch (all reads or all writes, never mixed):

[
  {"Statement": "DELETE FROM \"Orders\" WHERE PK = 'ORDER#1001' AND SK = 'META'"},
  {"Statement": "DELETE FROM \"Orders\" WHERE PK = 'ORDER#1002' AND SK = 'META'"}
]
aws dynamodb batch-execute-statement --statements file://statements.json

A WHERE that doesn't pin the full key fails — there is no DELETE FROM Orders WHERE status = 'archived'. More PartiQL patterns (and the limits behind them) in PartiQL examples and PartiQL vs SQL.

Deleting ALL items (truncate)

DynamoDB has no truncate. Your options, in order of preference:

  1. Delete and recreate the table. Item-by-item deletion of a whole table bills one write per item; DeleteTable + CreateTable sidesteps the entire write bill. The catch: table settings — indexes, TTL, , capacity mode, tags — don't come back on their own; you re-declare them at creation (infrastructure-as-code makes this a non-event).
  2. Expire items with . If "delete everything older than X" is really what you want, TTL deletes expired items in the background without consuming write capacity — a slow-motion bulk delete that costs nothing.
  3. Scan + batch-delete (Method 1) when the table must stay live and only a subset goes — you pay a read per item scanned plus a write per item deleted.

Delete multiple items in DynoTable

The select-then-delete flow above — query, collect keys, chunk, retry — is exactly the busywork a GUI should own. In DynoTable it's a grid selection:

  1. Run or filter a query so the rows you want gone are on screen.
  2. Select them and press ⌘⌫ — every selected row becomes a staged delete. Nothing has touched DynamoDB yet: the rows tint red in the grid and appear as reviewable cards in the staging panel.
  3. Review, then Commit. Commits ship as TransactWriteItems batches with optimistic-locking conditions — a staged delete only goes through if the item still exists — and large stages are automatically chunked to stay within DynamoDB's transaction limits. ⌘⇧⌫ skips the review and deletes-and-commits the selection in one chord.
Staged deletes in DynoTable: selected rows tinted red in the grid, each one a reviewable card in the staging panel before commit.
Staged deletes in DynoTable: selected rows tinted red in the grid, each one a reviewable card in the staging panel before commit.

The scope is honest: you delete the rows you selected — a reviewed, recoverable-until-commit operation — not a blind full-table truncate. For wiping an entire table, drop and recreate it (above).

If a delete needs a hand-written condition (attribute_exists, a version check), build the exact ConditionExpression + placeholder maps in the DynamoDB Expression Builder and attach it to a DeleteItem or transaction instead.

FAQ

Can I delete multiple items in one DynamoDB call? Yes — up to 25 with BatchWriteItem (best-effort, retry UnprocessedItems) or up to 100 atomically with TransactWriteItems. Both take a full primary key per item; neither accepts a "where" condition to select the items.

Is there a DELETE WHERE in DynamoDB? No. Neither the low-level API nor PartiQL can delete by condition — PartiQL's DELETE requires a WHERE that "resolve[s] to a single primary key value". You query or scan for the keys first, then delete each one.

How do I delete all items in a DynamoDB table? For a full wipe, delete and recreate the table — it avoids paying one write per item. For age-based cleanup, use TTL, which deletes expired items without consuming write capacity. Scan + batch-delete is the fallback when the table must stay live.

Why do items reappear after my batch delete? Almost always unretried UnprocessedItems: a throttled BatchWriteItem silently returns the failed deletes in the response, and code that doesn't loop over them "finishes" with items still in the table. Retry with exponential backoff until the map comes back empty.

How much does deleting items cost? Each delete is a standard write (one WCU per 1 KB, doubled inside a transaction), and finding the keys costs reads too. Estimate the damage with the pricing calculator.

Prefer to see what you're deleting first? Download DynoTable — select the rows, stage the deletes with ⌘⌫, review the diffs, and commit when you're sure.

Updated