DynamoDB Bulk Put Items Explained: Load S3 Data Into Existing Tables, Limits, Tiers and Costs
DynamoDB bulk put items loads S3 data into existing tables without using write capacity. Vs BatchWriteItem and Import from S3, quotas, tiers, costs.

Amazon DynamoDB can now bulk-load data from Amazon S3 into a table that already exists. AWS calls the feature bulk put items, and it became generally available on November 5, 2026. You point DynamoDB at JSON or Ion files in S3, and it writes the items asynchronously on separate capacity, so your app's reads and writes aren't throttled. Each item can carry its own condition, for example "insert only if it doesn't exist."
Until now, getting millions of rows into a live DynamoDB table meant writing your own BatchWriteItem loop (25 items per call), running a Glue or EMR job, or using Import from S3, which only creates a new table. Bulk put items fills that gap. Here's what it does, what it costs, its limits, and when you should still use BatchWriteItem.
What is DynamoDB bulk put items?
Bulk put items is a managed, asynchronous operation that reads objects from an S3 prefix and writes each record into an existing DynamoDB table. AWS's developer guide says the writes "run on a separate path and consume none of the table's read or write capacity," and items become readable as they're written.
You provide four things:
- The S3 location of your input files
- The target DynamoDB table
- An S3 location for the output report
- Optionally, a performance tier:
STANDARD(default) orACCELERATED
DynamoDB reads the objects, writes the items, handles retries, and writes a report of anything it couldn't write. AWS's launch blog post by Lee Hannigan and Anugrah Prakash lists daily ML-score refreshes, catalog enrichment, backfills and migrations as typical uses.
Bulk put items vs BatchWriteItem vs Import from S3
This is the comparison most developers will want first. All facts are from AWS documentation.
| BatchWriteItem | Import from S3 | Bulk put items (new) | |
|---|---|---|---|
| Target table | Existing | New table only | Existing |
| Size per call / job | Up to 25 put/delete requests, 16 MB per call | Job-based | Up to 100 GB (Standard) or 1 TB (Accelerated) per operation |
| Uses your table's write capacity | Yes | No (new table) | No, runs on separate capacity |
| Input formats | API request | CSV, DynamoDB JSON, Amazon Ion | DynamoDB JSON (JSON Lines), Amazon Ion |
| Compression | n/a | GZIP, ZSTD | GZIP, ZSTD, none |
| Per-item conditions | No | No | Yes, a ConditionExpression per record |
| Deletes | Yes | No | No, puts only |
| Global tables | Yes | n/a | Not supported |
| Synchronous? | Yes | No | No, you poll status |
| Best for | Small, immediate writes | Seeding a brand-new table | Large loads into a live table |
Note that CSV isn't supported. AWS's input-format documentation lists only DYNAMODB_JSON and ION.
How do you start a bulk put items job?
You call the new StartBulkPutItems API. AWS's docs give this AWS CLI example, which reads DynamoDB JSON files from one bucket and writes the error report to another:
aws dynamodb start-bulk-put-items \
--table-name MusicCollection \
--input-s3-configuration '{
"S3Bucket": "amzn-s3-demo-bucket",
"S3KeyPrefix": "daily/",
"InputFormat": "DYNAMODB_JSON",
"InputCompressionType": "NONE"
}' \
--output-s3-configuration '{
"OutputType": ["ERROR"],
"S3Bucket": "amzn-s3-demo-bucket1",
"S3KeyPrefix": "bulk-put-items-output/"
}' \
--performance-tier STANDARD
In Boto3 the method is start_bulk_put_items, and the response includes a BulkOperationArn. Other operations:
DescribeBulkOperationshows status and progress. CompareProcessedInputByteswithTotalInputBytes. AWS warns these are "not live counters," andTotalInputBytesappears only after initial validation.ListBulkOperationsreturns history. The launch blog says it covers 90 days.CancelBulkOperationstops a job. Items already written stay; nothing is rolled back.ClientTokenmakes a retried start idempotent. DynamoDB keeps the token for 8 hours.MaxWriteRequestUnitscaps how fast the job writes. The minimum is 1,024.
A job ends in one of four states: COMPLETED, COMPLETED_WITH_ERRORS (some records failed, see the report), FAILED (a systemic problem), or CANCELLED.
What does the input file look like?
Each line is one JSON object with an Item in DynamoDB's typed JSON, plus optional condition fields. This example from AWS's format docs mixes three behaviours in one file:
{"Item":{"id":{"S":"new-1"},"data":{"S":"hello"}},"ConditionExpression":"attribute_not_exists(id)"}
{"Item":{"id":{"S":"existing-1"},"data":{"S":"updated"}},"ConditionExpression":"#v = :expected","ExpressionAttributeNames":{"#v":"version"},"ExpressionAttributeValues":{":expected":{"N":"5"}}}
{"Item":{"id":{"S":"overwrite-1"},"data":{"S":"replaced"}}}
Line one inserts only if the key doesn't exist. Line two writes only if the stored version is 5. Line three has no condition, so it overwrites whatever is there.
Two details matter here:
- Conditions are per record, not per job. If you want insert-only behaviour for the whole file, every line needs its own
ConditionExpression. AWS's docs say you'll need to reprocess existing files to add one. - No condition means overwrite. A record without a condition replaces any existing item with the same primary key, just like
PutItem.
For migrations where newer data might already be in the table, AWS suggests a version guard such as attribute_not_exists(#v) OR #v < :new, which writes brand-new items and newer versions but skips stale ones.
Standard vs Accelerated: which tier should you pick?
| Standard | Accelerated | |
|---|---|---|
| Default? | Yes | No |
| Designed for | Cost-optimised loads where timing is flexible | Migrations, recovery, loads with a deadline |
| Max input per operation | 100 GB | 1 TB |
| Concurrent operations | 5 per account per Region | 5 per account per Region (counted separately) |
| Regions | All commercial Regions and AWS GovCloud (US) | 23 Regions listed in AWS docs, including N. Virginia, Ohio, Oregon, Ireland, Frankfurt, London, Tokyo, Sydney, Mumbai, São Paulo and GovCloud (US-West) |
| Tables with a vector index | Supported | Not supported |
AWS's tiers page gives estimated Accelerated completion times for 1 KB items: under 10 minutes for 10 million items, under an hour for 100 million, and 2-4 hours for 1 billion. Those numbers assume a well-scaled table, evenly spread partition keys, no secondary indexes, and input split across several similarly sized S3 objects. AWS also notes that early operations "may outpace table scaling," so the first runs on a fresh table can be slower.
What are the limits and quotas?
From AWS's DynamoDB service quotas page:
| Quota | Value |
|---|---|
| Concurrent operations, Standard | 5 per account (per Region) |
| Concurrent operations, Accelerated | 5 per account (per Region) |
| Active operations per table | 1 |
| Total input per operation | 100 GB (Standard), 1 TB (Accelerated) |
| Input objects per operation | 50,000 |
| Max size of each input object | 5 GB |
Minimum MaxWriteRequestUnits |
1,024 |
Starting a second job on a table that's already running one returns ResourceInUseException. Oversized input fails the job after it starts, with codes such as SizeLimitExceeded, S3ObjectsCountLimitExceeded or InputObjectTooLarge.
How much does DynamoDB bulk put items cost?
AWS says bulk put items "writes at a lower price point than the equivalent per-request writes." The on-demand pricing page bills it by GB written, with a 1 KB minimum per item, and each index write is metered separately. When we checked on November 8, we could not read the per-GB rate for either tier. The pricing table loads dynamically and we couldn't extract it reliably. Check the pricing page for your Region before running a large job.
Billing details from AWS's docs that are easy to miss:
- Failed condition checks are billed. An item that reaches the table and fails its condition is metered as a write. A condition check on a missing item counts as 1,024 base-table bytes.
- Validation failures aren't billed as table writes (for example, malformed records rejected before a write is attempted).
- GSIs and LSIs add cost. Bytes written to each secondary index count toward your bulk put usage.
- Reports cost S3 storage at normal S3 rates.
What should you check before running it?
AWS's best-practices page plus the considerations docs boil down to this checklist:
- Table isn't part of a global table. Bulk put items doesn't support them, and you can't add a replica mid-job.
- Table is
ACTIVEand not building a secondary index or restoring from backup. - Input is DynamoDB JSON Lines or Ion, one record per line, all objects under the prefix in the same format and compression.
- Input split into several similarly sized S3 objects, under 5 GB each.
- Every record that must not overwrite data has a
ConditionExpression. -
CONDITION_CHECK_FAILUREadded toOutputTypeif you want to see skipped items. - Stream consumers can keep up. Every bulk write produces a DynamoDB Streams or Kinesis record. Streams keep records for 24 hours, so a consumer more than a day behind loses data. Use
MaxWriteRequestUnitsto slow the job. - Nobody modifies the S3 objects while the job runs. AWS says that can fail the operation.
- Caller has
dynamodb:StartBulkOperation,dynamodb:BulkPutItems, S3 read on input, S3 write on the report bucket, and any KMS keys. DynamoDB uses the caller's credentials for S3, not a service principal.
One more subtle point from the docs: after an internal failover, DynamoDB can write some records a second time. If your application is also writing the same keys during the job, an unconditional repeat could overwrite a newer value. A version guard on each record prevents that.
Also note that bulk writes don't show up in the table's ConsumedWriteCapacityUnits metric or Contributor Insights. Your CloudWatch dashboards will look quiet during a big load. Monitor the job with DescribeBulkOperation and the S3 report instead.
What are developers saying?
We looked on Reddit's r/aws and developer forums and didn't find substantial public discussion of the launch yet, so we have no community reactions to quote. Based on Google search suggestions, people are asking about "dynamodb bulk insert," "dynamodb bulk update," "dynamodb batch put limit" and "dynamodb batch write size limit." The tables above answer the limit questions. Bulk put items doesn't do partial updates: each record is a full put of the item.
Editor's take
This is one of the most practical DynamoDB launches in a while, because it removes the scaffolding most teams built themselves: a Lambda or Glue job chewing through BatchWriteItem calls, retry logic for unprocessed items, and raising table capacity so the app doesn't get throttled. Separate capacity plus per-record conditions and an error report in S3 covers most of what those homemade loaders did.
The catches are real, though. Global tables are excluded, there's no CSV input, deletes and partial updates aren't supported, and failed conditions still cost money. The stream warning matters most in production: a 100-million-item load means 100 million stream records hitting your Lambda consumers. Start with a small Standard job against a staging table, read the report format, then scale up.
For other recent AWS cost and data changes, see our explainers on RDS per-snapshot billing and Graviton5 instances. In the same week, AWS also renamed Amazon Q Developer in the console to the AWS assistant.
FAQ
How do I bulk insert data into an existing DynamoDB table?
Put your data in S3 as DynamoDB JSON Lines or Amazon Ion, then call StartBulkPutItems (CLI: aws dynamodb start-bulk-put-items) with the input prefix, the table, and an S3 location for the report. The job runs asynchronously; poll DescribeBulkOperation for progress.
What is the BatchWriteItem limit in DynamoDB?
A single BatchWriteItem call can contain up to 25 put or delete requests and up to 16 MB of data, and each item can be up to 400 KB. Bulk put items isn't bound by the 25-item limit; it accepts up to 100 GB (Standard) or 1 TB (Accelerated) of input per operation.
Does DynamoDB bulk put items consume write capacity?
No. AWS says bulk writes run on a separate path and consume none of the table's read or write capacity. You're billed separately, per GB written.
Can I import a CSV into an existing DynamoDB table?
Not with bulk put items. It accepts only DynamoDB JSON and Amazon Ion. Import from S3 accepts CSV, but only into a new table. Convert CSV to DynamoDB JSON first.
Does bulk put items work with global tables?
No. AWS's docs say you can't start a bulk put items operation on a table that's part of a global table. Use BatchWriteItem or PutItem instead.
What's the difference between Import from S3 and bulk put items?
Import from S3 creates a new table from S3 data. Bulk put items writes into a table that already exists and adds per-item condition expressions.
Can I cancel a bulk put items job?
Yes, with CancelBulkOperation. Items already written stay in the table and aren't rolled back.
Is DynamoDB bulk put items available in every Region?
The Standard tier is available in all commercial AWS Regions and AWS GovCloud (US). The Accelerated tier is in a subset of 23 Regions listed in AWS's documentation.
Sources
- AWS What's New, Amazon DynamoDB now supports bulk put items (Nov 5, 2026): https://aws.amazon.com/about-aws/whats-new/2026/11/amazon-dynamodb-now-supports-bulk-put-items/
- AWS Database Blog, Introducing bulk put items for Amazon DynamoDB: https://aws.amazon.com/blogs/database/introducing-bulk-put-items-for-amazon-dynamodb-load-data-from-amazon-s3-into-existing-tables-at-scale/
- DynamoDB Developer Guide, Working with bulk put items: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BulkPutItems.HowItWorks.html
- DynamoDB Developer Guide, Performance tiers: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BulkPutItems.Tiers.html
- DynamoDB Developer Guide, Running a bulk put items operation: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BulkPutItems.Requesting.html
- DynamoDB Developer Guide, Input formats: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BulkPutItems.Format.html
- DynamoDB Developer Guide, Considerations, quotas and permissions: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BulkPutItems.Considerations.html
- DynamoDB Developer Guide, Best practices for bulk put items: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BulkPutItems.BestPractices.html
- DynamoDB service quotas: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ServiceQuotas.html
- DynamoDB API Reference, BatchWriteItem: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html
- DynamoDB Developer Guide, Import from S3: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/S3DataImport.HowItWorks.html
- DynamoDB on-demand pricing: https://aws.amazon.com/dynamodb/pricing/on-demand/
Featured image: Exterior of an AWS data center (Amazon press photo). Source