<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Uriel Bitton</title>
    <description>The latest articles on DEV Community by Uriel Bitton (@urielbitton).</description>
    <link>https://dev.to/urielbitton</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F300278%2Fb747ae00-0959-48dd-bed2-e7d478c72ed5.jpg</url>
      <title>DEV Community: Uriel Bitton</title>
      <link>https://dev.to/urielbitton</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/urielbitton"/>
    <language>en</language>
    <item>
      <title>Using Conditional Writes to Enforce Business Logic in DynamoDB</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Fri, 23 May 2025 12:23:21 +0000</pubDate>
      <link>https://dev.to/urielbitton/using-conditional-writes-to-enforce-business-logic-in-dynamodb-8ak</link>
      <guid>https://dev.to/urielbitton/using-conditional-writes-to-enforce-business-logic-in-dynamodb-8ak</guid>
      <description>&lt;p&gt;One of the most underrated features in DynamoDB is conditional writes.&lt;/p&gt;

&lt;p&gt;Most users treat DynamoDB as a simple key-value datastore: put an item in, get an item out.&lt;/p&gt;

&lt;p&gt;But DynamoDB has a wealth of powerful features to support most modern workloads.&lt;/p&gt;

&lt;p&gt;One of these is to enforce business logic directly at the database level (in an atomic operation) without needing extra read operations or middleware logic.&lt;/p&gt;

&lt;p&gt;This does a lot for performance and consistency in your database.&lt;/p&gt;

&lt;p&gt;Let’s break this down.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are conditional writes?
&lt;/h2&gt;

&lt;p&gt;In DynamoDB, you can use a ConditionExpression within the following write operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PutItem&lt;/li&gt;
&lt;li&gt;UpdateItem&lt;/li&gt;
&lt;li&gt;DeleteItem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tells DynamoDB to only perform the write if the given condition is met. Otherwise the write is rejected.&lt;/p&gt;

&lt;p&gt;This acts as a logic gate for writes.&lt;/p&gt;

&lt;p&gt;Imagine the following example: you want to create a user with a unique username.&lt;/p&gt;

&lt;p&gt;Usually to do this, you would need to have a read to check if the username exists and then do a write if it doesn’t (and return an error if it does).&lt;/p&gt;

&lt;p&gt;But with conditional writes, you can skip the read entirely.&lt;/p&gt;

&lt;p&gt;Here’s the code in a DynamoDB PutItem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await dynamodbClient.send(new PutItemCommand({
  TableName: "users",
  Item: marshall({
     username: "jason123",
     email: "jason@gmail.com",
  }),
  ConditionExpression: 'attribute_not_exists(username)'
}))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This write of a new user will only succeed if the username value does not exist in the table, effeciently enforcing uniqueness with one atomic operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some use cases for conditional writes
&lt;/h2&gt;

&lt;p&gt;Some useful use cases for conditional writes can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;preventing duplicate orders&lt;/li&gt;
&lt;li&gt;making sure a user doesn’t apply a coupon twice&lt;/li&gt;
&lt;li&gt;enforce account limits (e.g. max 5 devices per user)&lt;/li&gt;
&lt;li&gt;avoiding overwrites in race conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are all business logic constraints that commonly appear in applications.&lt;/p&gt;

&lt;p&gt;Conditional writes allow you to support these constraints with minimal latency and complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling conditional failures
&lt;/h2&gt;

&lt;p&gt;If a condition fails, DynamoDB will throw a &lt;strong&gt;ConditionalCheckFailedException&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can catch this error and return a more readable message to the user like:&lt;/p&gt;

&lt;p&gt;“This coupon has already been used”&lt;/p&gt;

&lt;p&gt;Remember, a conditional fail is expected behaviour, not a bug. So display it as the normal flow when an item already exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Conditional Expressions in DynamoDB are powerful and keep conditional writes more efficient.&lt;/p&gt;

&lt;p&gt;They let you enforce rules like uniqeness, resource limits, idempotency and concurrency control all at the database write layer with full atomicity.&lt;/p&gt;

&lt;p&gt;Whenever you need conditional writes in your application, verify if the condition can instead be done on your DynamoDB query before.&lt;/p&gt;




&lt;p&gt;👋 My name is Uriel Bitton and I’m committed to helping you master AWS, serverless and DynamoDB.&lt;/p&gt;

&lt;p&gt;🚀 Build the database your business needs with DynamoDB — subscribe to my email newsletter &lt;a href="https://urielbitton.substack.com/" rel="noopener noreferrer"&gt;The Serverless Spotlight&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading and see you in the next one!&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>database</category>
      <category>nosql</category>
      <category>conditionalwrites</category>
    </item>
    <item>
      <title>AWS Lambda Best Practices For Performant &amp; Scalable Serverless Functions</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Tue, 13 May 2025 14:36:56 +0000</pubDate>
      <link>https://dev.to/urielbitton/aws-lambda-best-practices-for-performant-scalable-serverless-functions-3ccp</link>
      <guid>https://dev.to/urielbitton/aws-lambda-best-practices-for-performant-scalable-serverless-functions-3ccp</guid>
      <description>&lt;p&gt;Serverless functions help you build powerful systems quickly and at a low initial cost.&lt;/p&gt;

&lt;p&gt;They are versatile in that they can fit small MVP workloads and large scalable enterprise systems.&lt;/p&gt;

&lt;p&gt;However, like any other tool, they must be used properly and with best practices.&lt;/p&gt;

&lt;p&gt;I’ve been building backend systems, for large and small companies, for over 6 years now and I’ll share with you some best practices and tips I’ve learned along the way.&lt;/p&gt;

&lt;p&gt;Use this article as a guide for every time you create a new Lambda function, to make sure it follows the best practices in this list.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Memory &amp;amp; Timeout
&lt;/h2&gt;

&lt;p&gt;The first thing you should be configuring as soon as you create a new Lambda function is the memory and timeout settings.&lt;/p&gt;

&lt;p&gt;These settings can be found in the General Configuration tab under the main Conguration tab.&lt;/p&gt;

&lt;p&gt;99.9% of your functions should have at least 500MB of memory. Anything lower than that will usually take longer than needed to run or timeout.&lt;/p&gt;

&lt;p&gt;The sweet spot for most functions is between 500MB and 1GB. If you have longer running workloads you can bring that up to 2–3GB.&lt;/p&gt;

&lt;p&gt;For the timeout, set a default of 3–5 seconds, depending on how long your functions tend to run. Monitor the timeout for your functions in CloudWatch and determine the best timeout for each function.&lt;/p&gt;

&lt;p&gt;That will optimize costs and performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Permissions
&lt;/h2&gt;

&lt;p&gt;Your Lambda function should respect the least privilege principle. In other words, it should be overly permissive yet have access to the services it communicates with.&lt;/p&gt;

&lt;p&gt;Rather than having an IAM role like “admin” (read/write any AWS service), or a role which has access to several different services, each function should have a role for the one thing it performs.&lt;/p&gt;

&lt;p&gt;For example, if your function is responsible for fetching items from DynamoDB, it should possess only a DynamoDB query role. Not a DynamoDB full access, read or read+write.&lt;/p&gt;

&lt;p&gt;The tighter the permissions control is on your Lambdas, the less room there is for error.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Concurrency
&lt;/h2&gt;

&lt;p&gt;Concurrency dictates how many times your Lambda function can be invoked at the same time.&lt;/p&gt;

&lt;p&gt;For higher traffic usage, you may need a higher amount.&lt;/p&gt;

&lt;p&gt;In the Configurations settings under concurrency and recursion detection you can set the concurrency for each function individually.&lt;/p&gt;

&lt;p&gt;The way it works is your account has a total quota of concurrency for all the Lambdas in it.&lt;/p&gt;

&lt;p&gt;Think of it as a pool of concurrency. If you need a certain amount of concurrency for a popular function, you can reserve 100 concurrency units for it.&lt;/p&gt;

&lt;p&gt;This will guarantee the function can always support no less and no more than 100 concurrent executions.&lt;/p&gt;

&lt;p&gt;This is what reserved concurrency means.&lt;/p&gt;

&lt;p&gt;If you leave the default (unreserved concurrency) this lets the function take as much concurrency as it needs without regards to other functions.&lt;/p&gt;

&lt;p&gt;So imagine you have a total of 100 account concurrency and you have 1 function using up 100 invocations at the same time, your other functions won’t be able to run as they will have no concurrency available to them to run.&lt;/p&gt;

&lt;p&gt;Setting reserved concurrency will guarantee that the function to never be starved of concurrency.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Versions
&lt;/h2&gt;

&lt;p&gt;Lambda versions let you publish immutable “snapshots” of your function code and configurations.&lt;/p&gt;

&lt;p&gt;This is particularly useful when you need to perform rollbacks or AB testing of your function.&lt;/p&gt;

&lt;p&gt;A best practice with versions is to publish a new version after every stable code change and use aliases like dev, satging, prod, to manage deployment stages safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Triggers
&lt;/h2&gt;

&lt;p&gt;Triggers come in handy when working with other AWS services like DynamoDB or S3.&lt;/p&gt;

&lt;p&gt;If you need to react to changes in S3 or DynamoDB and execute code with your Lambda function in response, triggers is what you need to use.&lt;/p&gt;

&lt;p&gt;For example, you can setup a DynamoDB or S3 trigger on your Lambda to do things like:&lt;/p&gt;

&lt;p&gt;calculate data in one table and write it to another DynamoDB table&lt;br&gt;
update an external search index whenever new data is written to my DynamoDB table&lt;br&gt;
Write a new item to my DynamoDB table every time a file is uploaded to S3&lt;/p&gt;

&lt;p&gt;The process is simple: add a trigger on the Lambda function, configure the trigger, write your Lambda code to capture the upstream data and finally push that data to a downstream service.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Environment Variables
&lt;/h2&gt;

&lt;p&gt;Environment variables are useful and important to set for hidden values and configuration variables.&lt;/p&gt;

&lt;p&gt;Typically, they are used to store values such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 bucket names&lt;/li&gt;
&lt;li&gt;DynamoDB table names&lt;/li&gt;
&lt;li&gt;API base URLs&lt;/li&gt;
&lt;li&gt;Config keys &amp;amp; non-sensitive credentials&lt;/li&gt;
&lt;li&gt;feature toggles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxl4xjqyvfl4c3f11zdwr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxl4xjqyvfl4c3f11zdwr.png" alt="Image description" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the screenshot above, you can see I use them specifically for a Algolia integration. I store my app id as an environment variable as well as the index name which is a configuration value.&lt;/p&gt;

&lt;p&gt;To add environment variables, select the Configuration tab and select environment variables in the left sidebar. From there you can add your variables.&lt;/p&gt;

&lt;p&gt;It is important to note not to use environment variables for secret keys or sensitive values. Those should be securely stored using AWS Secrets Manager.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article we went through several best practices of using AWS Lambda. These include configuring memory and timeout, concurrency, working with permissions and versions as well as setting triggers and environment variables.&lt;/p&gt;

&lt;p&gt;By following these best practices you can make sure your Lambda functions are secure, efficient and production-ready.&lt;/p&gt;

&lt;p&gt;Keep this guide as a checklist whenever you build or update your serverless functions.&lt;/p&gt;




&lt;p&gt;👋 My name is Uriel Bitton and I’m committed to helping you master AWS, serverless and DynamoDB.&lt;/p&gt;

&lt;p&gt;🚀 Build the database your business needs with DynamoDB — subscribe to my email newsletter &lt;a href="https://urielbitton.substack.com/" rel="noopener noreferrer"&gt;The Serverless Spotlight&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading and see you in the next one!&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>serverless</category>
      <category>aws</category>
      <category>bestpractices</category>
    </item>
    <item>
      <title>How to Think in Access Patterns First With DynamoDB</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Tue, 06 May 2025 14:34:17 +0000</pubDate>
      <link>https://dev.to/urielbitton/how-to-think-in-access-patterns-first-with-dynamodb-116a</link>
      <guid>https://dev.to/urielbitton/how-to-think-in-access-patterns-first-with-dynamodb-116a</guid>
      <description>&lt;p&gt;If you’ve spent years building apps on relational databases, switching to DynamoDB can feel very strange.&lt;/p&gt;

&lt;p&gt;I often tell folks to “forget everything you know” about relational databases.&lt;/p&gt;

&lt;p&gt;Designing data on DynamoDB requires a very different mindset.&lt;/p&gt;

&lt;p&gt;The biggest shift is that you don’t start with your data structure, you start with your access patterns.&lt;/p&gt;

&lt;p&gt;Understanding this concept will catapult you ahead of most folks building with DynamoDB.&lt;/p&gt;

&lt;p&gt;It’s a mindshift from “what data do I have?” to “how will users access my data”.&lt;/p&gt;

&lt;p&gt;Let’s break this concept in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  SQL vs. DynamoDB: The Mental Model Shift
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp4e4jx60kcxmk1vpfxz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvp4e4jx60kcxmk1vpfxz.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In SQL, you define your schema first and normalize data into tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;users&lt;/li&gt;
&lt;li&gt;posts&lt;/li&gt;
&lt;li&gt;comments&lt;/li&gt;
&lt;li&gt;likes&lt;/li&gt;
&lt;li&gt;shares&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You then query across tables using joins to fetch the data you need. This flexibility is simultaneously SQL’s strength and performance bottleneck.&lt;/p&gt;

&lt;p&gt;DynamoDB is drastically different.&lt;/p&gt;

&lt;p&gt;You have to think differently.&lt;/p&gt;

&lt;p&gt;You start with your use cases:&lt;/p&gt;

&lt;p&gt;How your application will write/read data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“What are the questions your application needs to answer”?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get all posts by a user within a specified date range&lt;/li&gt;
&lt;li&gt;fetch orders made by a user this month&lt;/li&gt;
&lt;li&gt;show a feed of user’s posts sorted by date published&lt;/li&gt;
&lt;li&gt;Get comments on a given post.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each one of these are access patterns and you model your table around these patterns specifically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Think in access patterns instead of queries
&lt;/h2&gt;

&lt;p&gt;Instead of starting with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“What tables do I need”?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ask yourself:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“What queries will my app need to support for its users (at scale and performance)”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, imagine you are building a marketplace application.&lt;/p&gt;

&lt;p&gt;Your app needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show all listings by a seller&lt;/li&gt;
&lt;li&gt;Fetch a listing by its ID&lt;/li&gt;
&lt;li&gt;Display orders for a buyer&lt;/li&gt;
&lt;li&gt;Show order status by orderID&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are your app’s main access pattern and each one needs to be efficient and satisfied with a single query operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the single table design pattern
&lt;/h2&gt;

&lt;p&gt;DynamoDB’s performance comes (in part) from avoiding joins and sticking to primary key lookups.&lt;/p&gt;

&lt;p&gt;This is why the single table design is the recommended approach.&lt;/p&gt;

&lt;p&gt;In this design strategy, you store different entity types (e.g. users, posts, comments, likes) in the same table.&lt;/p&gt;

&lt;p&gt;Each entity item is differentiated by a “PK” and “SK” composite key format. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PK        | SK
-------------------------
user#101  | profile
user#101  | post#201
user#101  | order#303
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This data model makes it easy to query the related data on your table with a single query.&lt;/p&gt;

&lt;p&gt;You can also avoid joins and multiple queries.&lt;/p&gt;

&lt;p&gt;If you’re curious about the single table design, I recommend this &lt;a href="https://medium.com/aws-in-plain-english/a-beginners-guide-to-the-single-table-design-in-dynamodb-79aa0e079484" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get started with DynamoDB Design
&lt;/h2&gt;

&lt;p&gt;Here’s a breakdown on getting started with your first DynamoDB database design process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;List every access pattern your app needs. (Don’t think about tables, just access patterns).&lt;/li&gt;
&lt;li&gt;Group them by common entity or user context.&lt;/li&gt;
&lt;li&gt;For each one, decide the ideal PK/SK structure that makes queries simple and efficient.&lt;/li&gt;
&lt;li&gt;Identify where you’ll need GSIs to support alternate lookups. (For each access pattern add a “table” or “GSI1” in parentheses after it)&lt;/li&gt;
&lt;li&gt;Once you’ve done all that, create a single table and store all your data on it. (read this article on how to do this)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Working with DynamoDB requires a large mindset shift.&lt;/p&gt;

&lt;p&gt;Forget what you know about SQL and learn to embrace access patterns first. This will help you build systems that are faster, cheaper, and scale effortlessly.&lt;/p&gt;

&lt;p&gt;The shift isn’t always easy, but it’s worth it and gets easier the more you work with DynamoDB.&lt;/p&gt;




&lt;p&gt;👋 My name is Uriel Bitton and I’m committed to helping you master AWS, serverless and DynamoDB.&lt;/p&gt;

&lt;p&gt;🚀 Build the database your business needs with DynamoDB — subscribe to my email newsletter &lt;a href="https://urielbitton.substack.com" rel="noopener noreferrer"&gt;The Serverless Spotlight&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading and see you in the next one!&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>database</category>
      <category>aws</category>
      <category>serverless</category>
    </item>
    <item>
      <title>How I Migrated An SQL Database To DynamoDB</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Wed, 16 Apr 2025 12:40:15 +0000</pubDate>
      <link>https://dev.to/urielbitton/how-i-migrated-an-sql-database-to-dynamodb-1io0</link>
      <guid>https://dev.to/urielbitton/how-i-migrated-an-sql-database-to-dynamodb-1io0</guid>
      <description>&lt;p&gt;Migrating an SQL database to NoSQL is always challenging.&lt;/p&gt;

&lt;p&gt;SQL models relational data while NoSQL can be designed for a very wide variety of data storage use cases.&lt;/p&gt;

&lt;p&gt;I recently had to migrate a legal database from MySQL to Amazon key-value database, DynamoDB.&lt;/p&gt;

&lt;p&gt;Amidst the challenges, the migration also forced me to make some tradeoff decisions to better adapt to DynamoDB’s scalable architecture.&lt;/p&gt;

&lt;p&gt;I’ll break down the migration process into the following three elements:&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the use cases and access patterns
&lt;/h2&gt;

&lt;p&gt;Understanding the relationships between data&lt;br&gt;
Choosing the best tradeoff with the existing constraints&lt;br&gt;
Let me take you through how each one posed its own challenge and what I did resolve them, in the hopes to offer a broad guideline if you have a similar migration workload.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding Use Cases &amp;amp; Access Patterns
&lt;/h2&gt;

&lt;p&gt;Since I was migrating the data to DynamoDB, the first step was to understand the nature of the application and its access patterns.&lt;/p&gt;

&lt;p&gt;The group of lawyers had various types of data stored on their MySQL database.&lt;/p&gt;

&lt;p&gt;Some of this data included:&lt;/p&gt;

&lt;p&gt;-customers data&lt;br&gt;
-dossiers data&lt;br&gt;
-meetings data&lt;br&gt;
-transactions data&lt;/p&gt;

&lt;p&gt;The main data access patterns were the following:&lt;/p&gt;

&lt;p&gt;-Getting a customer’s dossier(s)&lt;br&gt;
-Getting customers with a given status (in progress, accepted, rejected)&lt;br&gt;
-Getting all cases in the current month&lt;br&gt;
-Getting invoices for a given customers (by month/year).&lt;br&gt;
-Getting bill payments (transactions) for a given month&lt;/p&gt;

&lt;p&gt;There were a few more, but for the sake of brevity I’ll focus on these main ones.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding the relationships between data
&lt;/h2&gt;

&lt;p&gt;With MySQL, the database fetches would make a few joins to query customers with dossiers, customers with meetings, and customers with transactions (for billing puposes).&lt;/p&gt;

&lt;p&gt;When a new customer’s dossier was created by a lawyer, a customer record, a dossier and some initial invoicing data is created initially.&lt;/p&gt;

&lt;p&gt;Then as the lawyer meets with the customer, some meeting records get added (these would have the total duration and hourly rate, amongst some other metadata).&lt;/p&gt;

&lt;p&gt;If there was a court case (quite frequent), a case record was created with additional invoices (to be added as transactions when paid).&lt;/p&gt;
&lt;h2&gt;
  
  
  Design the Data For DynamoDB
&lt;/h2&gt;

&lt;p&gt;To migrate the data from MySQL to DynamoDB, I started with carefully designing a data model based on the access patterns identified.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting a customer’s dossier(s)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All customer dossier items in DynamoDB were transformed to have the following partition key (pk) and sort key (sk):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pk: “customer#101#dossiers”,
sk: “dossier#2025-01-01#201”,
entityType: “dossier”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In MySQL, a dossier record had a foreign key with the customer’s ID to query for dossiers belonging to that customer.&lt;/p&gt;

&lt;p&gt;In DynamoDB, I created an item collection — customer##dossiers — for all dossiers items for that customer.&lt;/p&gt;

&lt;p&gt;The sort key was defined as the date prefix (to sort dossiers by date created) and suffixed with a random uuid.&lt;/p&gt;

&lt;p&gt;(note: for userIds and dossierIds i’m using plain numbers like 101, 201, for simplicity. I do the same for the rest of the data below).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting customers with a given status&lt;/strong&gt;&lt;br&gt;
It was important for my client to be able to filter their customers by status. Each customer would have a status defined based on whether their dossier was accepted, rejected or in progress.&lt;/p&gt;

&lt;p&gt;In MySQL this was a plain value. Here’s how I designed it in DynamoDB.&lt;/p&gt;

&lt;p&gt;I created a GSI with attributes to satisfy this access pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pk: “customer#101#dossiers”,
sk: “dossier#2025-01-01#201”,
entityType: “dossier”,
GSI1PK: “dossiers#accepted”,
GSI1SK: “dossier#2025-01-01#201”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When creating a dossier item, I had to add the two attributes “GSI1PK” and “GSI1SK” — the first had the value of “dossier#” and the GSI1SK would keep the same value as the base table’s “sk” value.&lt;/p&gt;

&lt;p&gt;Using this GSI, I could easily get all dossiers that were of a given status by passing in the status into the “GSI1PK” value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting all cases in the current month&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cases were the less frequently written items to the database since these involved the lawyers going to court with their customers.&lt;/p&gt;

&lt;p&gt;As was the case, it was safe to store all case items in a partition prefixed by the current year.&lt;/p&gt;

&lt;p&gt;Here’s the primary key design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pk: “cases#2025”,
sk: “case#2025-01-01#301”,
entityType: “cases”
Getting invoices for a given customers.
Invoice items are part of the customer item collection.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s how they are represented in the new database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pk: “customer#101#invoices”,
sk: “invoice#2025-01-01#401”,
entityType: “invoices”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Getting bill payments for a given month&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bill payment records follow the same model as invoices. They are partitioned by customer since it is the customers that make the payments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pk: “customer#101#payments”,
sk: “payment#2025-01-01#501”,
entityType: “payments”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Choosing the best tradeoffs
&lt;/h2&gt;

&lt;p&gt;The main tradeoff was sacrificing some simplicity of join operations in MySQL with more effort on the database item primary key design.&lt;/p&gt;

&lt;p&gt;This involved more complex partition and sort key data modeling to “pre-join” items of different entities.&lt;/p&gt;

&lt;p&gt;For example, one access pattern would fetch a customer item, their invoices for the current month as well as any payments associated with it.&lt;/p&gt;

&lt;p&gt;Other tradeoffs included replicating items versus normalizing data.&lt;/p&gt;

&lt;p&gt;Much of the data that was normalized in the SQL database had to be denormalized and sometimes duplicated in DynamoDB.&lt;/p&gt;

&lt;p&gt;For example, if two lawyers worked on the same case, a case item had to be duplicated, one for each lawyer. This was designed as such to enable the access pattern where a lawyer could retrieve all cases assigned to them.`&lt;/p&gt;

&lt;h2&gt;
  
  
  The Migration Process
&lt;/h2&gt;

&lt;p&gt;The migration went mostly smooth after a lot of preparation.&lt;/p&gt;

&lt;p&gt;The data model for each record was carefully planned before the migration.&lt;/p&gt;

&lt;p&gt;Most of the normalized data was denormalized before as well.&lt;/p&gt;

&lt;p&gt;For the actual migration, I wrote one script per table.&lt;/p&gt;

&lt;p&gt;I scanned each table, read each item and wrote it to my single DynamoDB table, adding the primary keys, and other attributes.&lt;/p&gt;

&lt;p&gt;For the data that was normalized, I had to take that into consideration and create additional items to DynamoDB.&lt;/p&gt;

&lt;p&gt;Once all scripts ran successfully, I had some small modifications to do to make sure all items were consistent.&lt;/p&gt;

&lt;p&gt;Then came the post-migration, which required me to create serverless functions with AWS Lambda to satisfy the main access patterns to write new data to the DynamoDB table.&lt;/p&gt;

&lt;p&gt;The rest of that process can make for an interesting follow up article…&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Migrating my client’s database from SQL to DynamoDB required careful planning and tradeoff decisions to adapt to DynamoDB’s context.&lt;/p&gt;

&lt;p&gt;While the process involved tradeoffs like denormalizing data and designing complex primary key structures, it ultimately allowed for much more scalable and efficient data access patterns.&lt;/p&gt;

&lt;p&gt;The migration taught me a lot about how to think in NoSQL versus SQL and how data modeling in both systems involves different thinking and satisfying different problems.&lt;/p&gt;




&lt;p&gt;👋 My name is Uriel Bitton and I’m committed to helping you master AWS, serverless and DynamoDB.&lt;/p&gt;

&lt;p&gt;🚀 Build the database your business needs with DynamoDB — subscribe to my email newsletter &lt;a href="https://excelling-with-dynamodb.beehiiv.com/subscribe" rel="noopener noreferrer"&gt;Excelling With DynamoDB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading and see you in the next one!&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>database</category>
      <category>migration</category>
      <category>sql</category>
    </item>
    <item>
      <title>What Is Split For Heat In Amazon DynamoDB?</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Fri, 11 Apr 2025 13:21:59 +0000</pubDate>
      <link>https://dev.to/urielbitton/what-is-split-for-heat-in-amazon-dynamodb-31i3</link>
      <guid>https://dev.to/urielbitton/what-is-split-for-heat-in-amazon-dynamodb-31i3</guid>
      <description>&lt;p&gt;It is well known that Amazon DynamoDB adapts to workloads of any scale while offering consistent performance.&lt;/p&gt;

&lt;p&gt;But a lesser-known concept with its adaptive capacity features is “split for heat”.&lt;/p&gt;

&lt;p&gt;To understand what “split for heat” is we must first understand the reason behind it.&lt;/p&gt;

&lt;p&gt;In DynamoDB, your data is written to partitions on AWS’s storage servers.&lt;/p&gt;

&lt;p&gt;While a partition has a physical size limit, you as a customer, are not concerned with that nor will it affect you in any way. This is because DynamoDB will automatically manage partitions for you, creating new ones as your dataset grows.&lt;/p&gt;

&lt;p&gt;However, even though size limits is not an issue, hot partitions surely is one.&lt;/p&gt;

&lt;p&gt;A hot partition is a partition that is consistently receiving high traffic. This can impact read and write performance to and from that partition (when reading or writing items stored with that partition key).&lt;/p&gt;

&lt;p&gt;The standard prevention for a hot partition is high partition key cardinality.&lt;/p&gt;

&lt;p&gt;But a hot partition can still occur when you have an overly popular partition.&lt;/p&gt;

&lt;p&gt;This is where DynamoDB applies a strategy called “split for heat”.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Split For Heat?
&lt;/h2&gt;

&lt;p&gt;Split for heat is a mechanism where DynamoDB detects a partition that is receiving high traffic and automatically splits it into two smaller partitions.&lt;/p&gt;

&lt;p&gt;This helps reduce throttling and alleviates the performance impacts of reads and writes to that partition as you now have double the throughput available for that data (since it’s split into two).&lt;/p&gt;

&lt;p&gt;This is better than traditional sharding as it requires no manual intervention. DynamoDB will also determine when it is best to split it based on usage patterns.&lt;/p&gt;

&lt;p&gt;When splitting a partition, DynamoDB will distribute the items based on their sort key. This effectively doubles the available read and write throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does Split For Heat Work?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;DynamoDB will monitor for read and write traffic to its partitions. When a partition is identified as receiving sustained high traffic, it is marked as a candidate for splitting.&lt;/li&gt;
&lt;li&gt;The partition is split into two, with items distributed according to their sort key. Each new partition gets around half of the original items.&lt;/li&gt;
&lt;li&gt;Once the partition has been split, the total read/write capacity doubles, preventing throttling.&lt;/li&gt;
&lt;li&gt;While DynamoDB provides no notification when a split occurs, users will notice the reduction in throttling and better overall request handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices to maximize the benefits of Split For Heat
&lt;/h2&gt;

&lt;p&gt;Some best practices and design considerations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design partition keys carefully: even though DynamoDB can adapt to hot partitions, it’s always good to choose high cardinality partition keys to distribute writes evenly.&lt;/li&gt;
&lt;li&gt;Avoid time-based sort keys for high traffic items: if items in a partition have an ever-increasing sort key (e.g. timestamps), they will always be directed to a single partition, making the split for heat ineffective. Consider a more randomized sort key design in this case.&lt;/li&gt;
&lt;li&gt;Monitor and adjust: use Amazon CloudWatch to track read and write capacity usage and identify hot partitions before they impact your system’s performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Split for heat is one of DynamoDB’s most valuable features for managing unpredictable traffic use cases.&lt;/p&gt;

&lt;p&gt;While proper data modeling is crucial to prevent hot partitions, DynamoDB’s adaptive capacity features like split for heat make sure that even the highest traffic workloads don’t impact your system’s performance.&lt;/p&gt;




&lt;p&gt;👋 My name is Uriel Bitton and I’m committed to helping you master AWS, serverless and DynamoDB.&lt;/p&gt;

&lt;p&gt;🚀 Build the database your business needs with DynamoDB — subscribe to my email newsletter &lt;a href="https://excelling-with-dynamodb.beehiiv.com/subscribe" rel="noopener noreferrer"&gt;Excelling With DynamoDB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;☕️ Need help with DynamoDB? Book a 1:1 with me &lt;a href="https://calendly.com/urielas1/dynamodb-consultations" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading and see you in the next one!&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>split</category>
      <category>heat</category>
      <category>database</category>
    </item>
    <item>
      <title>Designing Time-Series Data In DynamoDB</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Sun, 06 Apr 2025 13:50:49 +0000</pubDate>
      <link>https://dev.to/urielbitton/designing-time-series-data-in-dynamodb-kcj</link>
      <guid>https://dev.to/urielbitton/designing-time-series-data-in-dynamodb-kcj</guid>
      <description>&lt;p&gt;DynamoDB is excellent at efficiently storing and querying time-series data.&lt;/p&gt;

&lt;p&gt;However, the efficiency remains entirely dependent on your ability to model your data properly to support the access patterns required.&lt;/p&gt;

&lt;p&gt;Improper data models can lead to higher costs and performance issues.&lt;/p&gt;

&lt;p&gt;Let’s explore some best practices and data models for storing and querying time-series data in DynamoDB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing a table for time-series data
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Choosing the right primary keys&lt;/strong&gt;&lt;br&gt;
Choosing the right partition key is essential for time-series data (and for any type of data in fact).&lt;/p&gt;

&lt;p&gt;A common design pattern is to prefix an identifier to the partition key and a high level time component. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pk: device#123#2025-03-21
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We add the “device” keyword followed by the device ID and then the date (without the time).&lt;/p&gt;

&lt;p&gt;The sort key should be a timestamp (in standardized ISO 8601 format) of the event to enable efficient range queries. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sk: time#2025-03-21T12:30:00Z
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So each reading from our device would be stored in this key structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Querying time-series data efficiently
&lt;/h2&gt;

&lt;p&gt;To fetch data for a specific time range, we can use the BETWEEN query method (rather than using inefficient Scan methods).&lt;/p&gt;

&lt;p&gt;Say we want to retrieve all readings from device 123 on March 21st 2025. We can run the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TableName: "devices",
KeyConditionExpression: "pk = :pk AND sk BETWEEN :start AND :end",
ExpressionAttributeValues: {
    ":pk": "device#123#2025-03-21",
    ":start": "time#2025-03-21T00:00:00Z",
    ":end": "time#2025-03-21T23:59:59Z"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By extending the start and end date we can expand our filter to whatever range we need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling high-traffic time-series workloads
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Partition Splitting to avoid hot keys&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A single partition can handle a total of 3000 read units and 1000 write units per second.&lt;/p&gt;

&lt;p&gt;If your time-series data has a high ingestion rate you can run into hot partitions.&lt;/p&gt;

&lt;p&gt;The solution for hot partitions is typically to shard the keys by more specific time components.&lt;/p&gt;

&lt;p&gt;For example, if you experience the “day” partitions experience heat, you can shard them by hour or minute.&lt;/p&gt;

&lt;p&gt;Rather than the partition key being “device#123#2025–03–21”, it can become “device#123#2025–03–21T12:00”.&lt;/p&gt;

&lt;p&gt;Now your data for that deviceID is partitioned by hour, reducing the risk of a hot partition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expiring Old Data&lt;/strong&gt;&lt;br&gt;
Time-series data often becomes obsolete after a certain amount of time.&lt;/p&gt;

&lt;p&gt;This is where using TTL is beneficial. Each item should have a TTL attribute so that it can automatically be removed by DynamoDB’s system.&lt;/p&gt;

&lt;p&gt;This optimizes storage costs and space on your table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storing Aggregated Data&lt;/strong&gt;&lt;br&gt;
Finally, if you often query summaries or aggregate totals, you can pre-aggregate data into a single item and query this item instead more efficiently.&lt;/p&gt;

&lt;p&gt;For example, instead of storing every event, you can store hourly or daily aggregation values with minimum, maximum and average values.&lt;/p&gt;

&lt;p&gt;To achieve this, you can use DynamoDB Streams. Every time a new event is recorded, use the stream to update a “count” value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Time-series data is often a great fit for DynamoDB, but as always efficient data modeling is critical.&lt;/p&gt;

&lt;p&gt;By designing your data to accommodate for BETWEEN query methods, you can retrieve time-series data in ranges very efficiently.&lt;/p&gt;

&lt;p&gt;Implementing these best practices mentioned will make sure you reduce query and storage costs and ensure high performance, low latency, and high scalability.&lt;/p&gt;




&lt;p&gt;👋 My name is Uriel Bitton and I’m committed to helping you master AWS, serverless and DynamoDB.&lt;/p&gt;

&lt;p&gt;🚀 Build the database your business needs with DynamoDB — subscribe to my email newsletter &lt;a href="https://excelling-with-dynamodb.beehiiv.com/subscribe" rel="noopener noreferrer"&gt;Excelling With DynamoDB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading and see you in the next one!&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>timeseries</category>
      <category>database</category>
      <category>data</category>
    </item>
    <item>
      <title>How I Migrate My Clients’ SQL Databases To DynamoDB</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Thu, 20 Mar 2025 14:06:16 +0000</pubDate>
      <link>https://dev.to/urielbitton/how-i-migrate-my-clients-sql-databases-to-dynamodb-2odd</link>
      <guid>https://dev.to/urielbitton/how-i-migrate-my-clients-sql-databases-to-dynamodb-2odd</guid>
      <description>&lt;p&gt;Migrating from a SQL database to DynamoDB is not a one-size-fits-all decision.&lt;/p&gt;

&lt;p&gt;It requires a deep understanding of access patterns, data modeling techniques, and costs. I only recommend this migration when there are clear performance or cost benefits.&lt;/p&gt;

&lt;p&gt;Here’s the structured approach I take when helping clients transition from SQL to DynamoDB.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. I Define Access Patterns First
&lt;/h2&gt;

&lt;p&gt;In SQL, data is normalized into multiple tables with relationships managed with foreign keys.&lt;/p&gt;

&lt;p&gt;However, in DynamoDB, the design is actually based on how the application queries and writes data.&lt;/p&gt;

&lt;p&gt;Before starting any migration, I like to list out every access pattern on the application. In other words, how data will be read and written.&lt;/p&gt;

&lt;p&gt;This step ensures that the database structure supports efficient queries without increases in cost or latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. I Choose the Right Primary Keys
&lt;/h2&gt;

&lt;p&gt;DynamoDB does not support traditional SQL joins.&lt;/p&gt;

&lt;p&gt;Instead, it relies on partition and sort keys. The selection of these keys directly impacts performance and scalability.&lt;/p&gt;

&lt;p&gt;A poor key selection can lead to hot partitions, causing slowdowns and increased costs.&lt;/p&gt;

&lt;p&gt;Because of this, I spend the most amount of time in the migration/design process defining my primary keys to ensure an efficient and scalable data model.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. I Denormalize Data Where Needed
&lt;/h2&gt;

&lt;p&gt;Unlike SQL, where data is spread across multiple tables and joined together at query time, DynamoDB takes advantage of denormalization instead.&lt;/p&gt;

&lt;p&gt;This means I’ll embed related data into a single item to reduce the number of read operations, which means duplicating data when necessary.&lt;/p&gt;

&lt;p&gt;By doing so, queries become faster and more efficient, avoiding expensive join-like operations in NoSQL; the primary latency reasons for SQL databases.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. I Use Global Secondary Indexes (GSIs) Instead of SQL Indexes
&lt;/h2&gt;

&lt;p&gt;SQL databases allow multiple indexes, but DynamoDB takes a different approach with GSIs.&lt;/p&gt;

&lt;p&gt;If an application requires querying data based on different attributes, I strategically implement GSIs.&lt;/p&gt;

&lt;p&gt;To optimize costs and performance, I apply key overloading, which allows me to use a single index for multiple query patterns rather than creating multiple GSIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. I Handle Transactions Differently
&lt;/h2&gt;

&lt;p&gt;DynamoDB supports transactions, but they come at twice the cost in terms of read and write capacity units.&lt;/p&gt;

&lt;p&gt;Instead of relying on transactions as frequently as in SQL, I use a single-table design with transactional writes only when necessary.&lt;/p&gt;

&lt;p&gt;This keeps operations efficient while maintaining data consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. I Test and Optimize Queries
&lt;/h2&gt;

&lt;p&gt;Every access pattern must be tested to ensure that the new database performs efficiently.&lt;/p&gt;

&lt;p&gt;I evaluate query performance, monitor read and write capacity usage, and optimize indexing strategies before fully transitioning to DynamoDB.&lt;/p&gt;

&lt;p&gt;Sometimes I may have to change a primary key design or a GSI to support a better access pattern.&lt;/p&gt;

&lt;p&gt;Other times, my clients may present me a revised or improved access pattern and I will then have to adjust my data model accordingly.&lt;/p&gt;

&lt;p&gt;Once everything is accounted for, it is time for the actual migration process.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Preferred Migration Strategy: Dual-Write Approach
&lt;/h2&gt;

&lt;p&gt;To ensure a smooth transition with minimal downtime, I typically implement a dual-write strategy.&lt;/p&gt;

&lt;p&gt;Here’s the step-by-step flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both the SQL database and DynamoDB receive new data writes.&lt;/li&gt;
&lt;li&gt;Reads continue to be served from the SQL database.&lt;/li&gt;
&lt;li&gt;Once the DynamoDB setup is validated and optimized, I’ll start cutting over read operations to it.&lt;/li&gt;
&lt;li&gt;After confirming stable performance (may take a few days to a few weeks), the SQL database is disconnected.&lt;/li&gt;
&lt;li&gt;DynamoDB becomes the primary database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gradual cutover method makes sure the migration is as smooth as possible while allowing time to validate data consistency and query performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Migrating from SQL to DynamoDB is not just about moving data; it requires, as I often say “a shift in mindset”.&lt;/p&gt;

&lt;p&gt;SQL focuses on normalization and relationships, whereas DynamoDB is built for scalability and optimized query performance.&lt;/p&gt;

&lt;p&gt;By carefully defining access patterns, choosing the right keys, denormalizing where necessary, using GSIs, and implementing an effective migration strategy, you can achieve a smooth and cost-efficient transition from any database to DynamoDB.&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>database</category>
      <category>migrate</category>
      <category>sql</category>
    </item>
    <item>
      <title>Why DynamoDB Doesn’t Let You Write A Bad Query</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Wed, 12 Mar 2025 14:49:03 +0000</pubDate>
      <link>https://dev.to/urielbitton/why-dynamodb-doesnt-let-you-write-a-bad-query-17k2</link>
      <guid>https://dev.to/urielbitton/why-dynamodb-doesnt-let-you-write-a-bad-query-17k2</guid>
      <description>&lt;p&gt;You’ve probably read this somewhere.&lt;/p&gt;

&lt;p&gt;“DynamoDB doesn’t let you write a bad query”.&lt;/p&gt;

&lt;p&gt;But what does it mean and how does DynamoDB accomplish this?&lt;/p&gt;

&lt;p&gt;To understand this we have to get into how DynamoDB works under the hood.&lt;/p&gt;

&lt;h2&gt;
  
  
  DynamoDB Data Structure
&lt;/h2&gt;

&lt;p&gt;DynamoDB is a distributed and fully managed NoSQL database that lets you easily scale.&lt;/p&gt;

&lt;p&gt;But how does it let you, the user, scale your database?&lt;/p&gt;

&lt;p&gt;Under the hood, DynamoDB stores your data in multiple servers called partitions.&lt;/p&gt;

&lt;p&gt;Your data is distributed across partitions, with the item’s partition key dictating the partition (using a hash function) where that item will be stored.&lt;/p&gt;

&lt;p&gt;With this architecture, a query you make to a partition (using a partition key) will be processed in O(1) time complexity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuxamb48iy5gyd9m587o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuxamb48iy5gyd9m587o.png" alt="Image description" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So no matter how you query with a partition key, the query will always be efficient (can’t make a bad query).&lt;/p&gt;

&lt;p&gt;That’s fine for partition key queries, but what about composite key queries; when you provide a sort key?&lt;/p&gt;

&lt;p&gt;Well, inside each partition, DynamoDB stores your items as a B-tree data structure. Think of this as an upside down tree where the root is the partition and all items inside it are leafs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mqfkx44ckhmrzzpwd7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mqfkx44ckhmrzzpwd7y.png" alt="Image description" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you add items to that partition, they are stored in an alphanumerically sorted order.&lt;/p&gt;

&lt;p&gt;For example, “ha” will be at the top of the structure, followed by “har”, then “hard”, “harm” and “harsh”. After all “ha…” items have been stored, items that start with “he…” will be stored (refer to screenshot above).&lt;/p&gt;

&lt;p&gt;Here’s what this means in terms of efficiency:&lt;/p&gt;

&lt;p&gt;Writing items to this partition will be done in worst case O(log n) — pretty fast.&lt;/p&gt;

&lt;p&gt;Reading data from this partition will be done in the same time complexity (O(log n)).&lt;br&gt;
From a high level overview, this is how data is stored in DynamoDB.&lt;/p&gt;

&lt;h2&gt;
  
  
  How DynamoDB doesn’t let you write a bad query
&lt;/h2&gt;

&lt;p&gt;So why does DynamoDB prevent you from writing bad or inefficient queries?&lt;/p&gt;

&lt;p&gt;It does this based on the data structure and some “clever limitations” it places around querying and writing.&lt;/p&gt;

&lt;p&gt;First, any single item write or read you make will remain efficient due to the data structure, as these operations would take O(log n) no matter how many items there are in the partition.&lt;/p&gt;

&lt;p&gt;Second, a query has a limit result set of 1mb. This limitation is designed so that the read latency stays low.&lt;/p&gt;

&lt;p&gt;While other NoSQL databases have a much higher limit, DynamoDB places a relatively low limit to keep queries fast.&lt;/p&gt;

&lt;p&gt;Additionally, for multiple item reads and writes, the partition key will greatly limit the search zone of your query.&lt;/p&gt;

&lt;p&gt;Similarly, the sort key is as well limited to a few query methods only, again to ensure efficiency and low latency.&lt;/p&gt;

&lt;p&gt;These query methods are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;equality operators (&amp;lt;, &amp;lt; =, &amp;gt;, &amp;gt; = and =): this lets you query for number or string values that are greater alphabetically or numerically than another value. (e.g. 5 &amp;gt; 7 or “ha” greater than “he”).&lt;/li&gt;
&lt;li&gt;begins_with() method: this lets you say “get me all items whose sort key begins with the substring x”. (e.g. begins_with(“ha”) will return “hard”, “harm”, “harsh”, etc.&lt;/li&gt;
&lt;li&gt;BETWEEN method: This lets you say “get me all items whose sort keys are between x and y”. (e.g. sort key BETWEEN “ha” and “hi”, will return “hard”, “harm”, “harsh”, “hello”, “hey”, until “hi”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now here’s why these query methods remain efficient even if your database contains billions of items.&lt;/p&gt;

&lt;p&gt;Notice how these methods respect the B-tree data structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeegb1pwlch21cccc971.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeegb1pwlch21cccc971.png" alt="Image description" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think of it as a dictionary. If you want to get all words that begin with the word “ha”, you could do it easily (and efficiently).&lt;/p&gt;

&lt;p&gt;You’d identify the “h” section (the partition) and find “ha”. From there you can sequentially trace through every word until you reach “he…”. (that’s the begins_with() method)&lt;/p&gt;

&lt;p&gt;You can also simulate the BETWEEN method with the dictionary approach. You can trace through every word that starts with “ha…” and ends with “hi”.&lt;/p&gt;

&lt;p&gt;However, in DynamoDB you can make a query in any other way such as saying “get me all items that contain a particular string like ‘er’”, just like with a dictionary you wouldn’t be able to find all words that contain the letters “er”.&lt;/p&gt;

&lt;p&gt;Or you might be able to but that would take you a really long time and require a full dictionary search.&lt;/p&gt;

&lt;p&gt;This is the strategy DynamoDB uses to make your queries scalable, fast and efficient.&lt;/p&gt;

&lt;p&gt;Now lets say you tried to design a bad, inefficient database structure and attempted to make a bad query, here’s what would happen.&lt;/p&gt;

&lt;p&gt;The query would still require a single partition (efficient).&lt;br&gt;
You can choose to specify a sort key but can only run it on sequential data, which is fast.&lt;/p&gt;

&lt;p&gt;If all items are in one partition and its a large partition, the query result would be limited to 1mb (wouldn't take too long to fetch).&lt;/p&gt;

&lt;p&gt;So no matter how you query your “badly designed” table, your query would remain relatively fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;DynamoDB’s architecture and query limitations are designed to enforce efficiency, and make sure that even a poorly designed schema won’t result in an inefficient query.&lt;/p&gt;

&lt;p&gt;Through the use of partitions, B-tree structures, and a limited set of query methods, DynamoDB guarantees predictable performance, preventing you from writing a “bad” query.&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>database</category>
      <category>aws</category>
      <category>query</category>
    </item>
    <item>
      <title>What Is Split For Heat In Amazon DynamoDB?</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Sat, 08 Mar 2025 00:05:41 +0000</pubDate>
      <link>https://dev.to/urielbitton/what-is-split-for-heat-in-amazon-dynamodb-bm8</link>
      <guid>https://dev.to/urielbitton/what-is-split-for-heat-in-amazon-dynamodb-bm8</guid>
      <description>&lt;p&gt;It is well known that Amazon DynamoDB adapts to workloads of any scale while offering consistent performance.&lt;/p&gt;

&lt;p&gt;But a lesser-known concept with its adaptive capacity features is "split for heat".&lt;/p&gt;

&lt;p&gt;To understand what "split for heat" is we must first understand the reason behind it.&lt;/p&gt;

&lt;p&gt;In DynamoDB, your data is written to partitions on AWS's storage servers.&lt;/p&gt;

&lt;p&gt;While a partition has a physical size limit, you as a customer, are not concerned with that nor will it affect you in any way. &lt;br&gt;
This is because DynamoDB will automatically manage partitions for you, creating new ones as your dataset grows.&lt;/p&gt;

&lt;p&gt;However, even though size limits is not an issue, hot partitions surely is one.&lt;/p&gt;

&lt;p&gt;A hot partition is a partition that is consistently receiving high traffic. This can impact read and write performance to and from that partition (when reading or writing items stored with that partition key).&lt;/p&gt;

&lt;p&gt;The standard prevention for a hot partition is high partition key cardinality.&lt;/p&gt;

&lt;p&gt;But a hot partition can still occur when you have an overly popular partition.&lt;/p&gt;

&lt;p&gt;This is where DynamoDB applies a strategy called "split for heat".&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Split For Heat?
&lt;/h2&gt;

&lt;p&gt;Split for heat is a mechanism where DynamoDB detects a partition that is receiving high traffic and automatically splits it into two smaller partitions.&lt;/p&gt;

&lt;p&gt;This helps reduce throttling and alleviates the performance impacts of reads and writes to that partition as you now have double the throughput available for that data (since it's split into two).&lt;br&gt;
This is better than traditional sharding as it requires no manual intervention. DynamoDB will also determine when it is best to split it based on usage patterns.&lt;/p&gt;

&lt;p&gt;When splitting a partition, DynamoDB will distribute the items based on their sort key. This effectively doubles the available read and write throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does Split For Heat Work?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feb1ze831d8tc34a0k75v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feb1ze831d8tc34a0k75v.jpg" alt="Image description" width="800" height="775"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DynamoDB will monitor for read and write traffic to its partitions. When a partition is identified as receiving sustained high traffic, it is marked as a candidate for splitting.&lt;/p&gt;

&lt;p&gt;The partition is split into two, with items distributed according to their sort key. Each new partition gets around half of the original items.&lt;/p&gt;

&lt;p&gt;Once the partition has been split, the total read/write capacity doubles, preventing throttling.&lt;/p&gt;

&lt;p&gt;While DynamoDB provides no notification when a split occurs, users will notice the reduction in throttling and better overall request handling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices to maximize the benefits of Split For Heat
&lt;/h2&gt;

&lt;p&gt;Some best practices and design considerations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design partition keys carefully: even though DynamoDB can adapt to hot partitions, it's always good to choose high cardinality partition keys to distribute writes evenly.&lt;/li&gt;
&lt;li&gt;Avoid time-based sort keys for high traffic items: if items in a partition have an ever-increasing sort key (e.g. timestamps), they will always be directed to a single partition, making the split for heat ineffective. Consider a more randomized sort key design in this case.&lt;/li&gt;
&lt;li&gt;Monitor and adjust: use Amazon CloudWatch to track read and write capacity usage and identify hot partitions before they impact your system's performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Split for heat is one of DynamoDB's most valuable features for managing unpredictable traffic use cases.&lt;/p&gt;

&lt;p&gt;While proper data modeling is crucial to prevent hot partitions, DynamoDB's adaptive capacity features like split for heat make sure that even the highest traffic workloads don't impact your system's performance.&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>split</category>
      <category>heat</category>
      <category>database</category>
    </item>
    <item>
      <title>Why You Shouldn't Use DynamoDB Filter Expressions And What To Use Instead</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Wed, 26 Feb 2025 17:42:23 +0000</pubDate>
      <link>https://dev.to/urielbitton/why-you-shouldnt-use-dynamodb-filter-expressions-and-what-to-use-instead-4dj</link>
      <guid>https://dev.to/urielbitton/why-you-shouldnt-use-dynamodb-filter-expressions-and-what-to-use-instead-4dj</guid>
      <description>&lt;p&gt;Last Friday I talked about DynamoDB on Zac's AWS Show.&lt;/p&gt;

&lt;p&gt;Here's some of the value I shared 👇&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 Why you don't want to use FilterExpressions
&lt;/h2&gt;

&lt;p&gt;FilterExpressions should be a last resort solution.&lt;/p&gt;

&lt;p&gt;They only filter the results after all items were fetched, losing the real benefit of filtering.&lt;/p&gt;

&lt;p&gt;How do you filter then?&lt;/p&gt;

&lt;p&gt;Use Sort keys...&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 How to use powerful filtering on your data
&lt;/h2&gt;

&lt;p&gt;Sort keys give you the opportunities to design for powerful filtering and sorting.&lt;/p&gt;

&lt;p&gt;In the video below I explain briefly how to overload your sort key to allow for this efficient filtering.&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 The 2 most important query methods to understand
&lt;/h2&gt;

&lt;p&gt;These are the:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;begins_with() method: the basis of filtering&lt;/li&gt;
&lt;li&gt;BETWEEN method: enables range type filtering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I show nice examples of these in the talk.&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 How GSIs work in DynamoDB
&lt;/h2&gt;

&lt;p&gt;GSIs allow for additional access patterns.&lt;/p&gt;

&lt;p&gt;A typical use case for a GSI is to create an inverted index for 1-many relationships.&lt;/p&gt;

&lt;p&gt;E.g. If your base table lets you get all students enrolled in a course, your inverted GSI index lets you get all courses that a student is taking.&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 The single table design
&lt;/h2&gt;

&lt;p&gt;Finally, i teased the single table design, the motivation behind it and some good use cases.&lt;/p&gt;

&lt;p&gt;Using one table instead of many is usually a better idea with DynamoDB.&lt;/p&gt;

&lt;p&gt;It offers much faster queries. &lt;/p&gt;

&lt;p&gt;The data that you query together should be stored together.&lt;/p&gt;

&lt;p&gt;It also offers lower costs if you are using provisioned capacity.&lt;/p&gt;

&lt;p&gt;That's it!&lt;/p&gt;

&lt;p&gt;If you missed it you can watch the recording here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/live/s8aRy2XIG18" rel="noopener noreferrer"&gt;Youtube Link&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Spent 5 Years Building With DynamoDB, Here Are My 3 Top Takeaways</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Sat, 22 Feb 2025 23:36:57 +0000</pubDate>
      <link>https://dev.to/urielbitton/i-spent-5-years-building-with-dynamodb-here-are-my-3-top-takeaways-4iin</link>
      <guid>https://dev.to/urielbitton/i-spent-5-years-building-with-dynamodb-here-are-my-3-top-takeaways-4iin</guid>
      <description>&lt;p&gt;Ispent the past 5 years building scalable databases for clients and organizations.&lt;/p&gt;

&lt;p&gt;Here are a few lessons I’ve learned along the way.&lt;/p&gt;

&lt;p&gt;A lot of these are issues a lot of DynamoDB users have and learning from these will set you up with an unfair advantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Understand your access patterns
&lt;/h2&gt;

&lt;p&gt;Before you start any database design with DynamoDB, stop and do this instead: identify and understand your data access patterns.&lt;/p&gt;

&lt;p&gt;What I mean by this is to take some time to find out how your users will be reading and writing data on your application.&lt;/p&gt;

&lt;p&gt;For example, are users browsing your products by category or rather by most popular? (it could be both)&lt;/p&gt;

&lt;p&gt;Do you allow sellers to add multiple products at a time or rather just one?&lt;/p&gt;

&lt;p&gt;By the manner your application fetches data most commonly that should tell you how you model it.&lt;/p&gt;

&lt;p&gt;Rather than using a general data model, model your data (that is primary keys) based on how they will be queried.&lt;/p&gt;

&lt;p&gt;If your application often queries users’ data along with their orders and purchase history, then you should store user info, orders and purchases using the same partition key.&lt;/p&gt;

&lt;p&gt;DynamoDB optimizes for latency at scale and designing based on your application’s access patterns will make or break that speed and scalability.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Partition Key design lets you scale
&lt;/h2&gt;

&lt;p&gt;Always think high cardinality first.&lt;/p&gt;

&lt;p&gt;High cardinality is simply a measure of uniqueness of your partition keys.&lt;/p&gt;

&lt;p&gt;A high cardinality partition key is for example “userID” or “productID” — there is usually just one in your database.&lt;/p&gt;

&lt;p&gt;A low cardinality partition key is for example “status” or “isFeatured” — there can be many shared values like “active” or “true/false”.&lt;/p&gt;

&lt;p&gt;The higher the partition key cardinality the better your database can scale. Partition keys that have too many shared values will run into hot partitions — partitions that get too much traffic.&lt;/p&gt;

&lt;p&gt;Your partition doesn’t always have to have a single unique value, sometimes you have no choice but to give it a value that will be shared. The thing to keep in mind here is when the partition key starts getting popular you should look towards sharding it.&lt;/p&gt;

&lt;p&gt;Sharding partition keys can be as simple as adding a prefix before the partition key name, such as a date or a location value. That can further make the partition higher in cardinality.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Sort Key design lets you filter
&lt;/h2&gt;

&lt;p&gt;DynamoDB’s API has a “FilterExpression” method. This lets you filter items will high flexibility.&lt;/p&gt;

&lt;p&gt;Don’t use it.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Well because FilterExpressions will fetch all of the data in the query and apply the filter after having fetched the data. This essentially means you are spending the same capacity units and costs without the filter operation.&lt;/p&gt;

&lt;p&gt;So how can you filter data in DynamoDB instead?&lt;/p&gt;

&lt;p&gt;Use the sort keys.&lt;/p&gt;

&lt;p&gt;Sort keys support the following query operations:&lt;/p&gt;

&lt;p&gt;= (equality)&lt;br&gt;
begins_with() (sort key starts with substring)&lt;br&gt;
&amp;lt;= (less than or equal to)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;= (greater than or equal to)&lt;br&gt;
BETWEEN (sort key is between value a and b)&lt;br&gt;
Using particularly the begins_with() operator, we can perform some powerful filtering.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, if we need to filter hotel rooms by features we can use the following sort key design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;room#&amp;lt;view-type&amp;gt;#&amp;lt;num-of-guests&amp;gt;#&amp;lt;features&amp;gt;#&amp;lt;floor-number&amp;gt;#&amp;lt;room-number&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e.g.: &lt;br&gt;
Room 1: "room#sea-view#2-guests#smoking#f1#101"&lt;br&gt;
Room 2: "room#sea-view#3-guests#smoking#f2#201"&lt;br&gt;
Room 3: "room#garden-view#4-guests#no-smoking#f3#301"&lt;br&gt;
With the data model above we can filter out rooms by their view, number of guests, features (like smoking allowed), floor number and room number.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://medium.com/aws-in-plain-english/how-i-would-design-the-data-model-for-a-hotel-booking-app-with-dynamodb-98769452e89e" rel="noopener noreferrer"&gt;this&lt;/a&gt; article, I go more into detail on using the begins_with() method to perform these powerful filtering strategies.&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>aws</category>
      <category>database</category>
      <category>takeaways</category>
    </item>
    <item>
      <title>Amazon DynamoDB Vs Google Firebase: Which Database To Choose For Your App?</title>
      <dc:creator>Uriel Bitton</dc:creator>
      <pubDate>Tue, 11 Feb 2025 15:45:25 +0000</pubDate>
      <link>https://dev.to/urielbitton/amazon-dynamodb-vs-google-firebase-which-database-to-choose-for-your-app-4k80</link>
      <guid>https://dev.to/urielbitton/amazon-dynamodb-vs-google-firebase-which-database-to-choose-for-your-app-4k80</guid>
      <description>&lt;p&gt;When it comes to building modern applications, choosing the right database is crucial.&lt;/p&gt;

&lt;p&gt;Two popular options in the cloud database space are Amazon DynamoDB and Google Firebase.&lt;/p&gt;

&lt;p&gt;While both are powerful tools, they offer different features and come with their own strengths and limitations.&lt;/p&gt;

&lt;p&gt;In this article, I’ll break down the main differences you should be concerned with to help you decide which one might be the best fit for your next application.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Use Cases
&lt;/h2&gt;

&lt;p&gt;At their core, DynamoDB and Firebase serve different purposes.&lt;/p&gt;

&lt;p&gt;DynamoDB is a fully managed NoSQL database designed for high-performance, scalable applications.&lt;/p&gt;

&lt;p&gt;It’s ideal for use cases like gaming, e-commerce, IoT data storage, and any application where low-latency and high data throughput is critical.&lt;/p&gt;

&lt;p&gt;On the other hand, Firebase is more than just a database — it’s an entire app development platform.&lt;/p&gt;

&lt;p&gt;Firebase Firestore is a NoSQL database that focuses on real-time data synchronization.&lt;/p&gt;

&lt;p&gt;It’s perfect for apps that require instant updates, like chat applications, collaborative tools, or live dashboards. Firebase also comes as a package with features like authentication, hosting, and analytics, making it quite versatile for various workload types.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Data Structure
&lt;/h2&gt;

&lt;p&gt;DynamoDB and Firebase handle data fetches and writes differently.&lt;/p&gt;

&lt;p&gt;DynamoDB stores data in a key-value and document format, which is highly flexible but requires careful planning of primary keys and indexes for efficient querying.&lt;/p&gt;

&lt;p&gt;It’s designed for predictable, and fast access patterns, but may be challenging when used with complex queries and filtering.&lt;/p&gt;

&lt;p&gt;Firebase Firestore uses a document-based model with collections and documents. It’s more intuitive for developers who want to store and retrieve hierarchical data.&lt;/p&gt;

&lt;p&gt;Firestore also supports real-time queries, meaning your app can listen for changes and update instantly. This makes Firebase a better choice for apps that need real-time functionality with virtually no backend setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Scalability
&lt;/h2&gt;

&lt;p&gt;Both databases are scalable, but they approach scalability differently.&lt;/p&gt;

&lt;p&gt;DynamoDB is built for massive scale and can handle millions of requests per second with consistent performance.&lt;/p&gt;

&lt;p&gt;It automatically partitions data across multiple servers, ensuring low latency even as your data grows. However, this scalability comes with a cost —scale can drive up pricing and requires careful capacity planning.&lt;/p&gt;

&lt;p&gt;Firebase is also scalable, but it’s more suited for small to medium-sized applications.&lt;/p&gt;

&lt;p&gt;While it can handle real-time updates efficiently, it isn’t designed for extremely high write loads like DynamoDB.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Ease of Use and Developer Experience
&lt;/h2&gt;

&lt;p&gt;When it comes to developer-friendliness, Firebase dominates in this area.&lt;/p&gt;

&lt;p&gt;Firebase’s SDKs are easy to integrate and the real-time features mean you can build real-time apps with very little effort.&lt;/p&gt;

&lt;p&gt;Firebase also provides a generous free tier, making it accessible for startups and small projects.&lt;/p&gt;

&lt;p&gt;You can check out the free tier and pricing plans here.&lt;/p&gt;

&lt;p&gt;DynamoDB has a steeper learning curve.&lt;/p&gt;

&lt;p&gt;It requires a deeper understanding of database design, including as I call it “re-wiring your SQL mind” to understand partition keys, sort keys, and secondary indexes.&lt;/p&gt;

&lt;p&gt;However, for developers who need fine-grained control over performance and scalability, DynamoDB’s raw power, scalability, and flexibility is a major advantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Pricing
&lt;/h2&gt;

&lt;p&gt;Pricing is another area where these two database services differ.&lt;/p&gt;

&lt;p&gt;DynamoDB charges based on read/write capacity units (RCUs/WCUs) or on-demand usage. This can get expensive for high-traffic applications, but you benefit in rare throttling and keeping a stellar user experience.&lt;/p&gt;

&lt;p&gt;With DynamoDB, you pay for what you use.&lt;/p&gt;

&lt;p&gt;Firebase uses a pay-as-you-go model based on the number of reads, writes, and storage.&lt;/p&gt;

&lt;p&gt;It has a generous free tier which makes it ideal for small projects. However, costs can add up quickly for apps with heavy real-time usage or large datasets.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Ecosystem and Integrations
&lt;/h2&gt;

&lt;p&gt;Both database services have great ecosystems — Firebase is part of Google’s cloud and DynamoDB is part of AWS’s cloud.&lt;/p&gt;

&lt;p&gt;Firestore integrates seamlessly with other Firebase services like Authentication, Cloud Functions, and Hosting. This is beneficial for full-stack app development.&lt;/p&gt;

&lt;p&gt;DynamoDB integrates well with other AWS services like Lambda, S3, and AppSync, amongst other widely used AWS services, making it a great fit for organizations already on AWS’s cloud platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Which One Should You Choose?
&lt;/h2&gt;

&lt;p&gt;As I’ve said before: the choice between DynamoDB and Firebase ultimately depends on your application’s needs.&lt;/p&gt;

&lt;p&gt;If you’re building a small to medium-sized real-time app with a focus on user interaction and ease of development, Firebase is probably a better choice.&lt;/p&gt;

&lt;p&gt;However, if you need a highly scalable, high-performance database for your application, DynamoDB is definitely your best bet. It’s a powerhouse for handling massive amounts of data with low latency, though it requires more upfront planning and expertise.&lt;/p&gt;

&lt;p&gt;The bottom line: it’s all about picking the database that aligns with your business and application’s needs, budget, and project requirements.&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>firebase</category>
      <category>aws</category>
      <category>database</category>
    </item>
  </channel>
</rss>
