{"id":2012,"date":"2026-07-22T23:00:22","date_gmt":"2026-07-22T17:30:22","guid":{"rendered":"https:\/\/lastroundai.com\/blog\/?post_type=iq&#038;p=2012"},"modified":"2026-07-21T20:29:48","modified_gmt":"2026-07-21T14:59:48","slug":"dynamodb","status":"publish","type":"iq","link":"https:\/\/lastroundai.com\/interview-questions\/dynamodb","title":{"rendered":"DynamoDB Interview Questions (2026): 51 Q&#038;As"},"content":{"rendered":"<p>A backend candidate at a mid-size logistics company got asked to design a schema for tracking package scans, one write per scan event, tens of thousands of packages moving through a handful of regional hubs at once. He reached for a relational instinct: a packages table, a scans table, a foreign key between them. The interviewer&#8217;s follow-up killed it in one sentence: what happens when every package scanned at the same hub in the same hour writes to the same partition. That&#8217;s the DynamoDB interview in miniature. The service looks like a key-value store with a friendly API, and most of the actual difficulty lives in key design decisions you make before you write a single query. AWS&#8217;s own developer guide frames the whole service around exactly this tradeoff, since a table&#8217;s partition and sort keys determine how data physically spreads across storage nodes (<a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/HowItWorks.html\" target=\"_blank\" rel=\"noopener noreferrer\">AWS DynamoDB Developer Guide<\/a>).<\/p>\n<p>Here&#8217;s a take that might be unpopular: most DynamoDB prep spends too much time on the CRUD API surface, PutItem, GetItem, UpdateItem, and not enough on capacity planning and access-pattern modeling, which is where interviewers actually differentiate candidates. You can memorize every API call in an afternoon. Understanding why a hot partition throttles your whole table even though your account-level throughput looks fine takes actual hands-on scar tissue, or at minimum a careful read of how DynamoDB&#8217;s quotas work under the hood.<\/p>\n<p>This page covers eight areas: the core data model (tables, items, attributes, primary keys), partition keys and secondary indexes, capacity modes and throughput, read consistency and Query versus Scan, writes and transactions, Streams and TTL and global tables, single-table design and hot partition mitigation, and day-two operations like DAX, backups, and throttling. Questions run from the kind asked in a phone screen through the kind that shows up in a staff-level system design loop.<\/p>\n<div class=\"iq-stats not-prose\"><div class=\"iq-stat\"><span class=\"iq-stat__value\">51<\/span><span class=\"iq-stat__label\">Questions<\/span><\/div><div class=\"iq-stat\"><span class=\"iq-stat__value\">400 KB<\/span><span class=\"iq-stat__label\">Max Item Size<\/span><\/div><div class=\"iq-stat\"><span class=\"iq-stat__value\">20 per table<\/span><span class=\"iq-stat__label\">Default GSI Limit<\/span><\/div><div class=\"iq-stat\"><span class=\"iq-stat__value\">5 per table<\/span><span class=\"iq-stat__label\">Default LSI Limit<\/span><\/div><\/div>\n<h2>Tables, items, and the primary key<\/h2>\n<p>Everything else on this page builds on how DynamoDB names and stores a single row. Get the vocabulary wrong here and the rest of the interview gets harder than it needs to be.<\/p>\n<div class=\"iq-dsec iq-dsec--easy\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"easy\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Easy questions<\/h2><span class=\"iq-dsec__n\">13<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What are the core building blocks of a DynamoDB table?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Fundamentals<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A table holds items, and each item is a collection of attributes, roughly a row and its columns in relational terms, except DynamoDB items in the same table don&#8217;t need the same set of attributes. One item might have twelve fields, another item in the same table might have three. The only thing every item in a table must share is the primary key, since that&#8217;s what DynamoDB uses to physically locate and retrieve it.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between a simple primary key and a composite primary key?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Primary Keys<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A simple primary key is just a partition key, one attribute, and it has to be unique across the whole table since it&#8217;s the only thing identifying an item. A composite primary key adds a sort key on top of the partition key, and now uniqueness is enforced on the pair together, not the partition key alone. That means you can have many items sharing the same partition key as long as each has a different sort key.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">json<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-json\">\n\n\/\/ Composite key example: an orders table\n\n{\n\n  \u201ccustomerId\u201d: \u201ccust_9182\u201d,   \/\/ partition key\n\n  \u201corderDate\u201d: \u201c2026-03-14\u201d,   \/\/ sort key\n\n  \u201ctotal\u201d: 89.50\n\n}\n\n\/\/ Same customerId, different orderDate, both valid, both items\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Can you change an item&#039;s primary key after it&#039;s written?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Primary Keys<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>No, not in place. The primary key is immutable for a given item, since it determines physical placement. To change it you delete the old item and write a new one with the new key values. This trips people who come from relational databases, where updating a primary key column, while rarely a good idea, is at least mechanically possible.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What data types does DynamoDB support for attributes?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Data Types<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Scalar types cover string, number, binary, boolean, and null. Document types cover list and map, which nest arbitrarily, a map inside a list inside a map is fine. Set types cover string set, number set, and binary set, which are unordered collections of unique values and behave differently from a list in that duplicates are silently rejected.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s a Global Secondary Index, and when do you reach for one?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Indexes<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A GSI is an index with its own partition key and optional sort key, different from the base table&#8217;s, letting you query the data by an access pattern the base table&#8217;s primary key doesn&#8217;t support. You reach for one whenever a real query in your application needs to filter or sort by an attribute that isn&#8217;t part of the base table key. A default table supports up to 20 GSIs, per the current AWS service quotas (<a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/Limits.html\" target=\"_blank\" rel=\"noopener noreferrer\">AWS DynamoDB quotas documentation<\/a>).<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the practical difference between on-demand and provisioned capacity mode?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Capacity Modes<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>On-demand is pay-per-request, no capacity planning, DynamoDB scales automatically to whatever the workload actually asks for and you&#8217;re billed for exactly what you use. Provisioned mode has you specify a fixed number of read and write capacity units up front, and you&#8217;re billed for what&#8217;s provisioned, whether you use all of it or not. AWS positions on-demand as the default and recommended mode for most workloads today, reserving provisioned mode for teams with steady, predictable traffic they can forecast accurately (<a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/HowItWorks.ReadWriteCapacityMode.html\" target=\"_blank\" rel=\"noopener noreferrer\">AWS DynamoDB capacity modes documentation<\/a>).<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What is a Read Capacity Unit, concretely?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Capacity Units<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>One RCU covers one strongly consistent read per second of an item up to 4 KB, or two eventually consistent reads per second of the same size. Reading a 10 KB item strongly consistent rounds up to 3 RCUs, since DynamoDB charges in whole 4 KB increments, not fractional ones.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between eventually consistent and strongly consistent reads?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Consistency<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>An eventually consistent read might return slightly stale data if it hits a replica that hasn&#8217;t caught up with the latest write yet, though in practice that window is usually well under a second. A strongly consistent read always returns the most recent successful write, at the cost of higher latency and double the RCU cost of the equivalent eventually consistent read. GetItem, Query, and Scan all default to eventually consistent unless you explicitly request strong consistency.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the practical difference between Query and Scan?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Query vs Scan<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Query requires a partition key and reads only the items in that one partition (optionally narrowed by a sort key condition), which makes it fast and cheap regardless of table size. Scan reads every item in the entire table (or index), then optionally filters after the fact, which means its cost scales with total table size, not with how many results you actually want back.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How does pagination work when a Query or Scan result is too large for one response?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Query vs Scan<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>DynamoDB caps a single Query or Scan response at 1 MB of data read, and if there&#8217;s more, the response includes a LastEvaluatedKey. You pass that value back in as ExclusiveStartKey on the next request to continue from exactly where the last one stopped. No LastEvaluatedKey in the response means you&#8217;ve reached the end.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What does a ConditionExpression on PutItem or UpdateItem actually do?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Conditional Writes<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>It attaches a condition that DynamoDB evaluates atomically against the item&#8217;s current state before applying the write. If the condition fails, the write is rejected and nothing changes, and the whole check-then-act happens as one atomic server-side operation, not two round trips from the client that could race against each other.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s an UpdateExpression, and why would you use it instead of overwriting the whole item with PutItem?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Updates<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>UpdateExpression lets you modify specific attributes on an item, SET a value, ADD to a number or a set, REMOVE an attribute entirely, without touching or even reading the rest of the item&#8217;s data. PutItem replaces the entire item, so if two processes PutItem the same key around the same time, whichever writes last silently wins and discards the other&#8217;s unrelated changes to different fields. UpdateExpression avoids that entirely by only touching the fields you name.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What is DynamoDB Streams, and what&#039;s a realistic use case for it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Streams<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Streams captures a time-ordered log of item-level changes, inserts, updates, deletes, on a table, retained for 24 hours, that other services can read and react to. A common pattern: a Lambda function subscribed to a table&#8217;s stream that fans out a notification, updates a search index, or replicates the change into an analytics pipeline, all without the original write path knowing or caring that any of that downstream work exists.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-dsec iq-dsec--medium\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"medium\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Medium questions<\/h2><span class=\"iq-dsec__n\">25<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why does DynamoDB need a primary key at all, given that it&#039;s schemaless for other attributes?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Primary Keys<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Because the primary key is the thing DynamoDB actually hashes to decide which physical partition an item lives on. Without a mandatory, consistently-typed key, the service has no deterministic way to route a read or write request to the right storage node in constant time. Every other attribute can vary freely between items precisely because the engine never needs them to locate anything, it only needs the key.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the maximum size of a single item, and what actually counts toward that limit?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Limits<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>400 KB per item, and that figure includes both attribute names and attribute values, not just the values. A table with long, descriptive attribute names on every item burns more of that budget than the same data with terse names, which is one reason some teams shorten attribute names in high-volume tables even though it hurts readability.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">If an item is close to the 400 KB limit, what design options do you have?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Limits<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Split the item across multiple items using a sort key range, storing the large payload as a separate item linked by the same partition key. If the oversized field is a blob rather than structured data, store it in S3 and keep only the S3 object key in DynamoDB. Compressing large text or JSON blobs before writing them also buys real headroom, since DynamoDB counts the stored bytes, not the pre-compression size.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How does DynamoDB decide which physical partition an item lands on?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Partitioning<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>It runs the partition key value through an internal hash function, and the output determines which physical partition stores the item. Two items with the same partition key always hash to the same partition, which is exactly why sort keys exist, to let you group related items together on one partition while still giving each a unique identity.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s a Local Secondary Index, and how is it fundamentally different from a GSI?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Indexes<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>An LSI shares the base table&#8217;s partition key but defines a different sort key, so it only lets you re-sort items within the same partition, not reroute them to a different one. A GSI can have a completely different partition key, effectively letting you query the table through a whole different access pattern. LSIs have to be created at table creation time and can&#8217;t be added later; GSIs can be added or removed at any point in a table&#8217;s life.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s index projection, and why would you choose KEYS_ONLY over ALL?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Indexes<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Projection controls which attributes get copied into the index alongside the key attributes. ALL copies every attribute from the base table item, KEYS_ONLY copies just the key attributes plus the index&#8217;s own key, and INCLUDE lets you name a specific list of extra attributes. KEYS_ONLY keeps the index small and cheap to write to, which matters if the index only exists to support existence checks or a follow-up GetItem, since a smaller index costs less storage and less write capacity per update to the base table.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">A GSI query is returning stale results right after a write. Is that a bug?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Consistency<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>No, that&#8217;s expected behavior, not a bug. GSIs are updated asynchronously after the base table write completes, so there&#8217;s a small propagation window, usually well under a second, where a read against the index might not reflect the very latest write. GSIs also only support eventually consistent reads, there&#8217;s no strongly consistent read option for a GSI the way there is for the base table or an LSI.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Can you add a Local Secondary Index to a table that already has data in it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Indexes<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>No. LSIs have to be defined at table creation and DynamoDB can never add one after the fact, precisely because they share the base table&#8217;s partitions and adding one retroactively would require re-partitioning existing data in a way the service doesn&#8217;t support. If you discover a new sort-order requirement after the table already exists and has real data, a GSI is the only option, since GSIs can be created, modified, and deleted on a live table at any time.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What is a Write Capacity Unit, and why does it cost more per byte than a read?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Capacity Units<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>One WCU covers one write per second of an item up to 1 KB, a quarter the size threshold a read gets for the same unit cost. Writes are simply more expensive work for the storage engine, since every write has to be durably persisted and replicated across multiple availability zones before it&#8217;s acknowledged, where an eventually consistent read can be served from a replica that&#8217;s slightly behind.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the default per-table throughput quota, and does it differ between capacity modes?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Quotas<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Both modes default to 40,000 read units and 40,000 write units per table, per current AWS quotas, though provisioned mode also has an account-level ceiling of 80,000 combined read and write capacity units across all tables in a region, while on-demand mode has no such account-level cap (<a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/Limits.html\" target=\"_blank\" rel=\"noopener noreferrer\">AWS DynamoDB quotas documentation<\/a>). All of these are soft limits that AWS will raise on request, not hard architectural ceilings.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">A junior engineer wrote a FilterExpression on a Scan and is confused why it&#039;s still slow and expensive at scale. What&#039;s happening?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Query vs Scan<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>FilterExpression runs after DynamoDB has already read every item and consumed the capacity for reading it, it only controls what gets returned to the client, not what gets read and billed. A Scan with a filter that only matches 1% of a 10 million item table still reads, and charges for, all 10 million items. The fix almost always isn&#8217;t a smarter filter, it&#8217;s replacing the Scan with a Query against a key (or a GSI key) that actually matches the access pattern.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Can Query use a FilterExpression too, and does it behave the same way as it does on a Scan?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Query vs Scan<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Yes, and the mechanics are identical: the filter applies after DynamoDB reads the items matching the key condition, so it doesn&#8217;t reduce the RCUs charged for that Query. The difference is scope. A Query&#8217;s key condition already narrows the read to one partition (and optionally a sort key range) before the filter ever runs, so the wasted read work is bounded by partition size, not table size, which is a much smaller blast radius than an unfiltered Scan.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What does the Limit parameter actually limit on a Query or Scan, and what&#039;s the common mistake candidates make about it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Query vs Scan<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Limit caps the number of items DynamoDB reads and evaluates per request, before any FilterExpression is applied, not the number of items returned after filtering. Set Limit to 10 with a filter that only matches 2 of them, and you get 2 items back, plus a LastEvaluatedKey telling you there&#8217;s more to page through, not automatically 10 filtered results. Candidates who assume Limit and &#8220;number of results&#8221; are the same thing usually get bitten by this exact gap the first time they add a filter to a paginated query.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How would you implement optimistic locking on a DynamoDB item without using transactions?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Optimistic Locking<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Keep a version attribute on the item, and on every update, include a ConditionExpression that the version attribute still equals the value you read, then increment it as part of the same write. If another process updated the item in between your read and your write, the condition fails and your write is rejected, telling you to re-read and retry instead of silently overwriting someone else&#8217;s change.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">json<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-json\">\n\n\/\/ Read: { \u201corderId\u201d: \u201co_5521\u201d, \u201cstatus\u201d: \u201cpending\u201d, \u201cversion\u201d: 3 }\n\n\/\/ UpdateItem with:\n\n\/\/ ConditionExpression: \u201cversion = :expectedVersion\u201d\n\n\/\/ UpdateExpression: \u201cSET status = :newStatus, version = version + :incr\u201d\n\n\/\/ If version isn\u2019t 3 anymore, the write fails\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between TransactWriteItems and BatchWriteItem?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Transactions<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>TransactWriteItems is all-or-nothing across up to 100 actions: if any single Put, Update, Delete, or ConditionCheck in the group fails, every action in the group rolls back and nothing is written. BatchWriteItem has no such guarantee, it&#8217;s just a convenience wrapper that sends multiple independent Put or Delete requests in one network call, and any individual request in the batch can succeed or fail on its own without affecting the others.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Does enabling transactions cost extra on a DynamoDB table?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Transactions<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>There&#8217;s no separate fee to turn transactions on, but each item involved in a TransactWriteItems or TransactGetItems call is billed at roughly double the normal capacity, since DynamoDB performs two underlying operations per item, one to prepare the transaction and one to commit it (<a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/transactions.html\" target=\"_blank\" rel=\"noopener noreferrer\">AWS DynamoDB transactions documentation<\/a>). A five-item transactional write costs roughly what ten individual writes would.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between the stream view types NEW_IMAGE, OLD_IMAGE, and NEW_AND_OLD_IMAGES?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Streams<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>NEW_IMAGE gives you the item as it looked immediately after the change, OLD_IMAGE gives you the item as it looked immediately before, and NEW_AND_OLD_IMAGES gives you both in the same stream record. You&#8217;d want both, for instance, if a downstream consumer needs to detect exactly which fields changed rather than just knowing the item changed at all.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How does Time to Live actually delete expired items, and is deletion instant the moment the TTL timestamp passes?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">TTL<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>You mark an attribute as the TTL attribute and store a Unix epoch timestamp in it per item. A background process scans for expired items and deletes them, but that deletion isn&#8217;t instant, AWS&#8217;s general guidance is that expired items are typically removed within 48 hours of the TTL timestamp, not the second it passes. Anything that assumes TTL deletion happens the moment an item expires, like using it as a precise scheduling mechanism, will produce surprising bugs.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s a global table, and what problem does it solve that a single-Region table plus your own replication code wouldn&#039;t?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Global Tables<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A global table replicates a table across multiple AWS Regions and keeps them in sync automatically, giving applications in each Region low-latency local reads and writes without you building and operating your own cross-Region replication pipeline. The classic case is a globally distributed user base where a user in Tokyo and a user in Frankfurt both want fast local reads against what functions as the same logical table.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What is single-table design, and why does DynamoDB push toward it more than a relational database would?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Single-Table Design<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Single-table design means modeling multiple, differently-shaped entity types, users, orders, product reviews, all in one physical DynamoDB table, using generic key attribute names like PK and SK whose actual meaning shifts depending on the entity type stored in that item. It&#8217;s driven by the fact that DynamoDB has no cheap join operation, so a relational instinct of &#8220;one table per entity type, join at query time&#8221; turns every multi-entity read into multiple round trips. Colocating related entities that get queried together, under the same partition key, turns what would be a join into a single Query call.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">json<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-json\">\n\n\/\/ One table, two entity types sharing a partition\n\n{ \u201cPK\u201d: \u201cCUSTOMER#9182\u201d, \u201cSK\u201d: \u201cPROFILE\u201d,         \u201cname\u201d: \u201cPriya R.\u201d }\n\n{ \u201cPK\u201d: \u201cCUSTOMER#9182\u201d, \u201cSK\u201d: \u201cORDER#2026-03-14\u201d, \u201ctotal\u201d: 89.50 }\n\n\/\/ A single Query on PK = CUSTOMER#9182 returns the profile and every order together\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Give a concrete example of write sharding to fix a hot partition.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Hot Partitions<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Say every write for a viral post&#8217;s like-counter hits the same partition key, postId. Instead of one key, shard it into a fixed number of buckets, postId#0 through postId#9, and have each write pick a bucket at random. Reading the total requires summing across all 10 buckets instead of one GetItem, which is a real added cost, but it&#8217;s a small, bounded cost compared to a partition throttling every write during a traffic spike.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">json<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-json\">\n\n\/\/ Instead of: { \u201cPK\u201d: \u201cPOST#5521\u201d, \u201clikes\u201d: 48213 }\n\n\/\/ Shard into:\n\n{ \u201cPK\u201d: \u201cPOST#5521#0\u201d, \u201clikes\u201d: 4801 }\n\n{ \u201cPK\u201d: \u201cPOST#5521#1\u201d, \u201clikes\u201d: 4790 }\n\n\/\/ \u2026through POST#5521#9, summed on read\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What is DAX, and what specific latency problem does it solve that provisioned throughput alone doesn&#039;t?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">DAX<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>DynamoDB Accelerator is an in-memory, write-through cache that sits in front of a table and serves reads in microseconds instead of the single-digit milliseconds a direct table read typically takes. It solves latency for read-heavy, repeat-key access patterns, a product page hit thousands of times a minute, not throughput problems, since DAX still has to write through to the table on every write and still respects the table&#8217;s own capacity limits underneath it.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Does DAX help with a write-heavy workload the same way it helps reads?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">DAX<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Not really. Writes still go straight through DAX to the underlying table and pay the table&#8217;s normal write cost and latency, DAX doesn&#8217;t buffer or batch writes to reduce that cost. Its value is almost entirely on the read side, and a workload that&#8217;s mostly writes with few repeated reads of the same items won&#8217;t see much benefit from adding it.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between on-demand backups and point-in-time recovery?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Backups<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>An on-demand backup is a full, manually-triggered snapshot you keep as long as you want, useful before a risky schema migration or a major deploy. Point-in-time recovery, once enabled, continuously backs up changes and lets you restore the table to any second within a retention window, useful for the &#8220;someone deleted the wrong items 6 hours ago&#8221; scenario where you don&#8217;t have a snapshot from exactly that moment.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">A team&#039;s DynamoDB bill spiked hard month over month with no code change, on an on-demand table. What&#039;s the first thing you&#039;d check?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Cost<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Scan usage, first. A Scan added anywhere in the request path, a background job, a debugging endpoint left in production, an admin report that used to run against a small table, gets dramatically more expensive as the table grows, since its cost scales with total table size regardless of how few rows actually match. I&#8217;d also check for a new GSI that&#8217;s projecting ALL attributes when it only needs a couple, since that inflates the write cost of every base table write, not just the queries against the index.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-dsec iq-dsec--hard\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"hard\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Hard questions<\/h2><span class=\"iq-dsec__n\">13<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why does AWS cap Local Secondary Indexes at 5 per table but allow up to 20 Global Secondary Indexes?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Indexes<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>An LSI shares storage with the base table&#8217;s partition, since it&#8217;s just an alternate sort order within the same physical partition. That means every LSI you add eats into the same 10 GB per-partition storage ceiling and the same per-partition throughput as the base table data, so DynamoDB caps the count tightly to protect that shared budget. A GSI is a genuinely separate index with its own partitions and its own provisioned or on-demand capacity, so it doesn&#8217;t compete with the base table&#8217;s per-partition limits the same way, which is why AWS can afford a much higher default quota there.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">You&#039;re designing an e-commerce orders table. Customers need to look up their own orders by date, and support needs to look up any order by its order ID. How would you key this?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Design<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Base table primary key: customerId as partition key, orderDate (or a composite orderDate#orderId to keep sort keys unique when a customer places two orders the same day) as sort key. That directly serves the customer-facing query, a Query on a single partition key, sorted by date, no index needed. For support&#8217;s lookup-by-order-ID pattern, add a GSI with orderId as its partition key. Support&#8217;s queries are rarer and lower-volume than the customer-facing path, which is exactly the kind of access pattern a GSI exists to support without forcing you to compromise the base table&#8217;s key design.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">json<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-json\">\n\n\/\/ Base table item\n\n{\n\n  \u201ccustomerId\u201d: \u201ccust_9182\u201d,           \/\/ PK\n\n  \u201corderDate#orderId\u201d: \u201c2026-03-14#o_5521\u201d, \/\/ SK\n\n  \u201corderId\u201d: \u201co_5521\u201d,                 \/\/ also projected into a GSI\n\n  \u201cstatus\u201d: \u201cshipped\u201d\n\n}\n\n\/\/ GSI: partition key = orderId, sort key = none needed for a unique lookup\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why would provisioned mode ever throttle requests if the account still has plenty of headroom left?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Throttling<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Capacity in provisioned mode is allocated per partition, not just per table. DynamoDB spreads a table&#8217;s total provisioned throughput evenly across its partitions, so if traffic concentrates on one partition key, that single partition can exhaust its slice of capacity and start throttling requests even though the table&#8217;s aggregate provisioned capacity, summed across all partitions, is nowhere near used up. Adaptive capacity mitigates this by shifting throughput toward hot partitions automatically, but it isn&#8217;t instantaneous, and a sudden spike can still throttle before adaptive capacity catches up.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">If you decrease provisioned capacity on a table too many times in one day, what happens?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Quotas<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>You hit a rate limit on decreases specifically, not increases. AWS gives a table 4 available capacity decreases at the start of each UTC day, refilling one more every hour up to that cap of 4, which works out to up to 27 total decreases across a full 24-hour day. Increases have no equivalent daily cap, which makes sense given the asymmetry: AWS wants to make it easy to scale up under load and slightly harder to thrash the billing down and up repeatedly.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How does DynamoDB guarantee a TransactWriteItems call doesn&#039;t get applied twice if the client retries after a network timeout?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Transactions<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Through an optional ClientRequestToken you can attach to the request. If the same token shows up again within a roughly 10-minute idempotency window, DynamoDB recognizes the retry and returns the original result without re-applying the writes a second time. Without a token, a client that times out waiting for a response has no safe way to know whether the transaction actually committed before retrying, and a naive retry risks double-applying the writes.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why can&#039;t TransactGetItems and TransactWriteItems span more than one region?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Transactions<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>ACID transactions require a single coordinator that can see and lock every item involved at the same moment before committing, and cross-region replication in DynamoDB (including global tables) is asynchronous by design, built for availability and low write latency in each region rather than for a synchronous cross-region lock. Multi-Region Strong Consistency global tables are the newer exception to this, letting reads and writes get strong consistency guarantees across replicas in specific configurations, but the classic transaction APIs remain single-Region operations.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What happens if two ConditionCheck actions in the same TransactWriteItems call reference the same item?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Transactions<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>DynamoDB rejects the whole request with a validation error before it even attempts the transaction. Every action within a single TransactWriteItems call must target a distinct item, you can&#8217;t have two actions, whether both ConditionChecks, or a ConditionCheck and an Update, pointed at the same primary key in one transaction. If your logic genuinely needs to both check and update the same item, fold the condition into the Update action&#8217;s own ConditionExpression instead of using a separate ConditionCheck.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How many consumers can reliably read from the same DynamoDB Streams shard at the same time?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Streams<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Up to two, for a single-Region table. Beyond that, AWS&#8217;s own documentation warns you&#8217;ll start seeing request throttling on the shard, and for global tables specifically, AWS recommends limiting it to a single reader per shard to avoid throttling entirely (<a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/Limits.html\" target=\"_blank\" rel=\"noopener noreferrer\">AWS DynamoDB quotas documentation<\/a>). Teams that need more than two consumers of the same change feed usually fan the stream out through Lambda or Kinesis Data Streams for DynamoDB instead of attaching multiple readers directly to the same shard.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Do TTL deletions show up in DynamoDB Streams the same way a manual DeleteItem call would?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">TTL<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Yes, a TTL-triggered deletion produces a stream record just like any other delete, but it&#8217;s tagged with a specific identifier marking it as a system delete rather than a user-initiated one, so downstream consumers can distinguish the two if the distinction matters to them. This is genuinely useful: a stream consumer archiving deleted records to S3 for compliance can treat TTL expirations differently from an accidental application-level delete.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s a genuine downside of single-table design, not just a purist objection?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Single-Table Design<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Honestly, the biggest one is that it front-loads almost all the design cost. You have to know every access pattern your application will ever need before you finalize the key schema, since changing a partition or sort key structure after the table is populated with real production data is a genuinely painful migration, usually a full rewrite into a new table. A relational schema tolerates &#8220;we&#8217;ll add an index for that later&#8221; far more gracefully than a single-table DynamoDB design does. I&#8217;d still reach for single-table design on a well-understood domain with stable access patterns. I&#8217;d hesitate on a genuinely exploratory product where the queries are still shifting month to month.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What causes a hot partition, and what design changes actually fix it, as opposed to just papering over it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Hot Partitions<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A hot partition happens when one partition key value receives a disproportionate share of read or write traffic relative to the others, since DynamoDB&#8217;s per-partition capacity is a hard physical ceiling regardless of the table&#8217;s total provisioned or on-demand capacity. Adaptive capacity helps by shifting some throughput toward the hot partition automatically, but it&#8217;s a mitigation, not a fix, and it can&#8217;t rescue a design where every single write genuinely targets the same key, a global counter incremented by every user, say. The actual fix is usually key sharding: append a random or hashed suffix to the hot key so writes spread across several logical partitions, then fan out reads across all the suffixes and merge results in the application.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why does a sequential, ever-increasing partition key, like a timestamp or an auto-incrementing ID, tend to create hot partitions in write-heavy tables?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Hot Partitions<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Because every new write lands on whatever the &#8220;latest&#8221; key range is, which DynamoDB has already routed to a specific, small set of physical partitions. All your write traffic concentrates on that recent range instead of spreading across the full key space the table&#8217;s partitions are distributed over. A random or well-distributed hash-based key, or a sharded key like the post-likes example, spreads new writes across partitions from the start instead of concentrating them on whatever&#8217;s most recent.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What does the DynamoDB table class &#039;Standard-Infrequent Access&#039; actually trade off against the default Standard class?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Cost<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Standard-IA charges roughly 60% less per GB of storage than the default Standard class, but charges more per read and write request unit in exchange. It&#8217;s the right call for tables that hold a lot of data but see relatively light, infrequent read and write traffic against it, an audit log you&#8217;re required to retain but rarely query, for instance, and the wrong call for a table with heavy request volume, where the higher per-request cost would outweigh whatever you saved on storage.<\/p>\n<p><\/div><\/div><\/div>\n<h2>How to prepare for a DynamoDB interview<\/h2>\n<p>Skip the flashcard approach to the API surface. Build one small thing that forces you to actually hit these tradeoffs: a chat app&#8217;s message history modeled with a composite key, a like-counter you deliberately overload with concurrent writes until you watch it throttle, then fix with sharding. Turn on DynamoDB&#8217;s request metrics in CloudWatch while you do it and watch ConsumedReadCapacityUnits and ThrottledRequests move in response to your own traffic. Reading about a hot partition is not the same as watching one happen to code you wrote an hour ago.<\/p>\n<p>Across backend mock interviews run through LastRoundAI, the GSI-versus-LSI question and the Query-versus-Scan cost question come up in roughly the same conversation more often than not, since they&#8217;re really the same underlying idea, know your access pattern before you pick a tool, asked two different ways. Candidates who can explain one but not the other usually memorized rather than understood the distinction. We don&#8217;t track a precise percentage split on that pattern, it&#8217;s an observation from reviewing sessions, not a measured statistic.<\/p>\n<p>One correction to something I said earlier in this piece: I called Scan-with-filter a design mistake, full stop. That&#8217;s not quite fair. A Scan is the right, and only, tool for a genuinely rare full-table operation, a one-time data migration script, an ad hoc analytics export you run once a quarter. The actual mistake is a Scan sitting in a hot request path that runs on every page load.<\/p>\n<h2>Get the reps in before the real thing<\/h2>\n<p><a href=\"\/products\/mock-interviews\">LastRoundAI&#8217;s mock interview mode<\/a> runs live system design and coding rounds with real-time follow-up questions, the same kind of pressure-test a hot-partition question actually creates in a real loop. The free plan includes 15 credits a month that reset monthly rather than piling up unused, and Starter is $19\/mo if a handful of sessions isn&#8217;t enough runway.<\/p>\n<p>Once your answers hold up under a follow-up, <a href=\"\/products\/auto-apply\">Auto-Apply<\/a> queues tailored applications for backend and infrastructure roles for your review, 10 a month on the free plan, up to 400 a month on the Ultimate plan, and nothing goes out until you approve it.<\/p>\n<p>Questions about either product go to contact@lastroundai.com. That&#8217;s the only inbox we check.<\/p>\n<div class=\"iq-sources not-prose\"><div class=\"iq-sources__title\">Sources &amp; further reading<\/div><ul class=\"iq-sources__list\"><li><a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/HowItWorks.html\" target=\"_blank\" rel=\"nofollow noopener\">AWS DynamoDB Developer Guide, How It Works<\/a><\/li><li><a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/HowItWorks.ReadWriteCapacityMode.html\" target=\"_blank\" rel=\"nofollow noopener\">AWS DynamoDB Read\/Write Capacity Modes<\/a><\/li><li><a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/Limits.html\" target=\"_blank\" rel=\"nofollow noopener\">AWS DynamoDB Quotas (Service Quotas)<\/a><\/li><li><a href=\"https:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/developerguide\/transactions.html\" target=\"_blank\" rel=\"nofollow noopener\">AWS DynamoDB Transactions<\/a><\/li><\/ul><\/div>\n","protected":false},"excerpt":{"rendered":"<p>A backend candidate at a mid-size logistics company got asked to design a schema for tracking package scans, one write per scan event, tens of thousands of packages moving through a handful of regional hubs at once. He reached for a relational instinct: a packages table, a scans table, a foreign key between them. The&#8230;<\/p>\n","protected":false},"author":7,"featured_media":2037,"comment_status":"open","ping_status":"closed","template":"","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"tags":[],"class_list":["post-2012","iq","type-iq","status-publish","has-post-thumbnail","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>DynamoDB Interview Questions (2026): Q&amp;A | LastRoundAI<\/title>\n<meta name=\"description\" content=\"51 real DynamoDB interview questions with answers: partition keys, GSI vs LSI, capacity modes, transactions, streams, TTL, and hot partition fixes explained.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/lastroundai.com\/interview-questions\/dynamodb\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"DynamoDB Interview Questions (2026): Q&amp;A | LastRoundAI\" \/>\n<meta property=\"og:description\" content=\"51 real DynamoDB interview questions with answers: partition keys, GSI vs LSI, capacity modes, transactions, streams, TTL, and hot partition fixes explained.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/lastroundai.com\/interview-questions\/dynamodb\" \/>\n<meta property=\"og:site_name\" content=\"LastRound AI\" \/>\n<meta property=\"og:image\" content=\"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-dynamodb-og.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"26 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/dynamodb\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/dynamodb\",\"name\":\"DynamoDB Interview Questions (2026): Q&A | LastRoundAI\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/dynamodb#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/dynamodb#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/iq-dynamodb-og.png\",\"datePublished\":\"2026-07-22T17:30:22+00:00\",\"description\":\"51 real DynamoDB interview questions with answers: partition keys, GSI vs LSI, capacity modes, transactions, streams, TTL, and hot partition fixes explained.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/dynamodb#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/dynamodb\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/dynamodb#primaryimage\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/iq-dynamodb-og.png\",\"contentUrl\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/iq-dynamodb-og.png\",\"width\":1200,\"height\":630,\"caption\":\"DynamoDB interview questions \u2014 LastRoundAI\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/dynamodb#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/lastroundai.com\\\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Interview Questions\",\"item\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"DynamoDB Interview Questions (2026): 51 Q&#038;As\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/\",\"name\":\"LastRound AI\",\"description\":\"Interview Assistant prep, tech careers and AI tools\",\"publisher\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#organization\",\"name\":\"LastRound AI\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png\",\"contentUrl\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png\",\"width\":400,\"height\":400,\"caption\":\"LastRound AI\"},\"image\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"DynamoDB Interview Questions (2026): Q&A | LastRoundAI","description":"51 real DynamoDB interview questions with answers: partition keys, GSI vs LSI, capacity modes, transactions, streams, TTL, and hot partition fixes explained.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/lastroundai.com\/interview-questions\/dynamodb","og_locale":"en_US","og_type":"article","og_title":"DynamoDB Interview Questions (2026): Q&A | LastRoundAI","og_description":"51 real DynamoDB interview questions with answers: partition keys, GSI vs LSI, capacity modes, transactions, streams, TTL, and hot partition fixes explained.","og_url":"https:\/\/lastroundai.com\/interview-questions\/dynamodb","og_site_name":"LastRound AI","og_image":[{"width":1200,"height":630,"url":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-dynamodb-og.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"26 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/lastroundai.com\/interview-questions\/dynamodb","url":"https:\/\/lastroundai.com\/interview-questions\/dynamodb","name":"DynamoDB Interview Questions (2026): Q&A | LastRoundAI","isPartOf":{"@id":"https:\/\/lastroundai.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/lastroundai.com\/interview-questions\/dynamodb#primaryimage"},"image":{"@id":"https:\/\/lastroundai.com\/interview-questions\/dynamodb#primaryimage"},"thumbnailUrl":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-dynamodb-og.png","datePublished":"2026-07-22T17:30:22+00:00","description":"51 real DynamoDB interview questions with answers: partition keys, GSI vs LSI, capacity modes, transactions, streams, TTL, and hot partition fixes explained.","breadcrumb":{"@id":"https:\/\/lastroundai.com\/interview-questions\/dynamodb#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/lastroundai.com\/interview-questions\/dynamodb"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/lastroundai.com\/interview-questions\/dynamodb#primaryimage","url":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-dynamodb-og.png","contentUrl":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-dynamodb-og.png","width":1200,"height":630,"caption":"DynamoDB interview questions \u2014 LastRoundAI"},{"@type":"BreadcrumbList","@id":"https:\/\/lastroundai.com\/interview-questions\/dynamodb#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/lastroundai.com\/blog"},{"@type":"ListItem","position":2,"name":"Interview Questions","item":"https:\/\/lastroundai.com\/interview-questions"},{"@type":"ListItem","position":3,"name":"DynamoDB Interview Questions (2026): 51 Q&#038;As"}]},{"@type":"WebSite","@id":"https:\/\/lastroundai.com\/blog\/#website","url":"https:\/\/lastroundai.com\/blog\/","name":"LastRound AI","description":"Interview Assistant prep, tech careers and AI tools","publisher":{"@id":"https:\/\/lastroundai.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/lastroundai.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/lastroundai.com\/blog\/#organization","name":"LastRound AI","url":"https:\/\/lastroundai.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/lastroundai.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/06\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png","contentUrl":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/06\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png","width":400,"height":400,"caption":"LastRound AI"},"image":{"@id":"https:\/\/lastroundai.com\/blog\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq\/2012","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq"}],"about":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/types\/iq"}],"author":[{"embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/comments?post=2012"}],"version-history":[{"count":1,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq\/2012\/revisions"}],"predecessor-version":[{"id":2064,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq\/2012\/revisions\/2064"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/media\/2037"}],"wp:attachment":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/media?parent=2012"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/tags?post=2012"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}