Feature Store's 25-entry batch write replaces the per-record loop with a retry handler
Two new SageMaker Feature Store APIs retire a per-record call loop and a tier where lost identifiers meant lost data. The batch write asks you to reconcile partial failures yourself, and the entry cap still sets a request floor.
The Engineer · Build desk

What happened
- AWS added BatchWriteRecord to SageMaker Feature Store, taking up to 25 records across multiple feature groups in one call with partial-success semantics, per-record TTL control and PutRecord's EventTime ordering.
- The existing PutRecord writes one record to one feature group per call, so high-throughput pipelines call it in a loop and pay connection overhead on every record they ingest.
- AWS's illustration is a fraud-detection pipeline ingesting 10,000 records a second across five feature groups, which has to sustain 50,000 individual API calls a second just to keep features current.
- Teams on the In-Memory storage tier could not browse or enumerate records, so identifiers lost to a bug or a pipeline failure left those records permanently unrecoverable.
- The second API, ListRecords, pages through record identifiers in a feature group and works on both the DynamoDB-backed Standard tier and the Redis-backed In-Memory tier.
Why it matters
- decision The loop cannot simply be deleted. Whoever owns the ingestion job now owns a reconciliation path for entries that fail on their own, which is new code to test rather than code removed.
- constraint Batching moves the bottleneck rather than removing it: at the volumes AWS cites the request rate stays in the thousands per second, so throttling headroom and client concurrency still need sizing.
- capability In-Memory feature groups become enumerable without an external index of identifiers maintained alongside them, which was the only thing making that tier survivable.
- cost The gate is a dependency bump: none of this is reachable until ingestion jobs move to a current Boto3 or SageMaker Python SDK v3.8.0 or later, with data plane permissions on the execution role.
Start with the conditional write, because that is the part the batch call does not change. PutRecord carries an EventTime, and the record becomes the latest version in the online store only if that EventTime beats what is already stored [6]. A record that loses the comparison is not dropped; it is written as a historical version to the offline store, for feature groups that have offline storage [7]. BatchWriteRecord preserves that same comparison per entry [3]. The write work per record is therefore identical. What goes away is one request and one connection setup per record, which is where the N x M pattern was spending its tail latency [8].
The saving is worth quantifying, since AWS supplies the inputs. Its example pipeline needs 50,000 calls a second [9], which is a thorough way to discover where your account's throttling limits sit. Divide that by the 25-entry ceiling and the floor is 2,000 requests a second [18]. The full 25-fold reduction only holds if every request is packed, and a single request can span feature groups [13], so the packing is at least achievable: five groups, five records each, one call. Real arrival rates are less obliging. A window that waits to fill 25 slots adds delay to the freshest feature, which is the feature the online store exists to serve. For that 2,000 to transfer to your pipeline, records have to arrive in groups of about 25 inside whatever staleness budget your model tolerates.
The failure surface changes shape as well. Each entry succeeds or fails on its own [10]. The response returns only the failures, split between Errors, which come back with the original record attached, and UnprocessedEntries, which are retriable; anything named in neither list succeeded [11]. Silence means success, so the client has to parse the body rather than check a status code, and AWS's guidance is to retry only the failed records with exponential backoff [12].
ListRecords is the smaller API and the larger repair. The In-Memory tier is Redis-backed [4], and it had no offline store to fall back on and no Athena query to run [15]. Identifiers lost to a bug or a failed pipeline took the records with them, permanently [14]. Paginated enumeration of identifiers [4] is precisely the primitive whose absence left that tier one bug away from silent data loss.
One case the ordering description leaves open. A stale-EventTime record aimed at an In-Memory feature group has no offline store to be filed into, because the historical-version path is scoped to feature groups with offline storage and the In-Memory tier has none [19]. The published walkthrough cuts off mid-example, so this may be spelled out elsewhere in the API reference. If you are relying on historical versions to build training sets, that is a reason to keep Standard tier groups in the picture regardless.
What to watch
- Whether ListRecords carries a page-size or request-rate limit that makes enumerating a very large feature group impractical inside a recovery window.
- Whether AWS documents partial-success behaviour when entries in one BatchWriteRecord request target feature groups on different storage tiers.
- Whether per-record TTL control can shorten an existing record's TTL on update, which decides whether it is usable for deletion deadlines.
Clarity's read
What the record supports and how the coverage leans. The claims behind it follow.
Reality
- Evidence62
- Adoption15
- Hype gap+12
- Incentives78
- Confidence60
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
Amazon SageMaker Feature Store is a fully managed repository to store, share and manage ML features, providing low-latency online serving for real-time inference, an offline store for historical retention and training data, and support for streaming and batch ingestion.
- [2]
AWS announced two new APIs for Amazon SageMaker Feature Store: BatchWriteRecord and ListRecords.
- [3]
BatchWriteRecord writes up to 25 records across multiple feature groups in a single API call, with partial-success semantics, per-record time-to-live (TTL) control, and the same EventTime-based ordering guarantees as PutRecord.
- [4]
ListRecords enumerates record identifiers within a feature group using pagination, and works with both the Standard (Amazon DynamoDB-backed) and In-Memory (Redis-backed) storage tiers.
- [5]
The existing PutRecord API writes one record to one feature group per call, so teams running high-throughput feature pipelines must call it in a loop, one API call per record per feature group, creating connection overhead and poor throughput.
- [6]
Each PutRecord call performs a conditional write: the record is persisted as the latest version only if the EventTime included in the request is newer than the existing record.
- [7]
If the EventTime condition fails, the record is still written as a historical version to the offline store, for feature groups with offline storage.
- [8]
At scale the single-record design forces an N x M calling pattern (N records x M feature groups), creating connection overhead and tail latency that limit throughput.
- [9]
AWS's example: a fraud-detection pipeline ingesting 10,000 records per second across five feature groups must sustain 50,000 individual API calls per second only to keep features current.
- [10]
BatchWriteRecord is a partial-success API: each record succeeds or fails independently, and individual record failures do not fail the entire request.
- [11]
The BatchWriteRecord response returns only the records that failed: records failing for reasons such as authentication, validation or throttling come back with error details and the original record, unprocessed requests come back as UnprocessedEntries which can be retried, and records listed in neither Errors nor UnprocessedEntries succeeded.
- [12]
AWS advises that the application should retry only the failed records, using exponential backoff for retriable errors.
- [13]
BatchWriteRecord accepts up to 25 entries in a single request targeting one or more feature groups simultaneously.
- [14]
Teams using the In-Memory storage tier had no way to browse or enumerate records stored in the online store, so if record identifiers were lost through a bug or pipeline failure those records became permanently unrecoverable.
- [15]
For the In-Memory tier there is no offline store to fall back on, no Amazon Athena query to run, and no API to discover what exists.
- [16]
The prerequisites for the examples include Boto3 (latest version) or SageMaker Python SDK v3.8.0 or later.
- [17]
The prerequisites also include an Amazon SageMaker AI execution role with access to Amazon S3 and AWS Glue plus permissions to interact with Feature Store data plane APIs, and the post publishes the minimum required IAM policy.
- [18]
At AWS's example volume of 50,000 calls per second, a fully packed 25-entry BatchWriteRecord request would reduce the request rate to 2,000 per second, a 25-fold reduction in call count.
- [19]
A record whose EventTime is not newer has no documented historical destination when it targets an In-Memory feature group, because the offline-store fallback is scoped to feature groups with offline storage and the In-Memory tier has no offline store.
Get this ledger inside ChatGPT. Ask about any of our stories and the answer brings its figure, each claim’s verdict and the sources. Free, no account.
Sources
1 independent publisher whose own reporting we read for this story.
- aws.amazon.comBatch write and discover records in Amazon SageMaker Feature Store
1 article · August 28, 2026
Topics and entities
Follow any of these and your For You feed starts watching them — no settings page required.
Topics
Entities
- Amazon Simple Storage ServiceFollow
- BatchWriteRecordFollow
- Amazon DynamoDBFollow
- Amazon Web ServicesFollow
- SageMaker Python SDKFollow
- boto3Follow
- ListRecordsFollow
- PutRecordFollow
- Amazon AthenaFollow
- AWS GlueFollow
- Amazon SageMaker Feature StoreFollow
- RedisFollow