<?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: João Victor Mazagão</title>
    <description>The latest articles on DEV Community by João Victor Mazagão (@jmazagao).</description>
    <link>https://dev.to/jmazagao</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%2F1684304%2F06522cf4-5a86-437b-8e1a-c811e227a23f.png</url>
      <title>DEV Community: João Victor Mazagão</title>
      <link>https://dev.to/jmazagao</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jmazagao"/>
    <language>en</language>
    <item>
      <title>The Enterprise Comfort Zone: When DevOps Teams Make You Forget How to Deploy</title>
      <dc:creator>João Victor Mazagão</dc:creator>
      <pubDate>Fri, 30 May 2025 16:53:35 +0000</pubDate>
      <link>https://dev.to/jmazagao/the-enterprise-comfort-zone-when-devops-teams-make-you-forget-how-to-deploy-2jd0</link>
      <guid>https://dev.to/jmazagao/the-enterprise-comfort-zone-when-devops-teams-make-you-forget-how-to-deploy-2jd0</guid>
      <description>&lt;p&gt;When starting to develop a new website or product, we face some challenges so easy to understand but so hard to fix. Today, after 8 years of developing all kinds of products, I faced the most insignificant problem to be solved by a developer: configure your environment variables for a deploy.&lt;/p&gt;

&lt;p&gt;Yesterday, working on my personal blog, I had an idea: why not configure a headless CMS to get my resume data to be easy to manage? &lt;/p&gt;

&lt;p&gt;Thriving on the idea, in my mind I was "this is gonna last no more than 10 minutes. It's gonna be easy. 10 minutes" As a Backend Engineer with a reasonable DevOps background, this should be easy. But it was painfully hard to solve and understand WHAT THE HECK is happening.&lt;/p&gt;

&lt;p&gt;What was I Expecting to do?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configure Contentful to retrieve my data (easy)&lt;/li&gt;
&lt;li&gt;Plug the Contentful package and consume the data (easy)&lt;/li&gt;
&lt;li&gt;Consume data locally (easy)&lt;/li&gt;
&lt;li&gt;Deploy using GitHub Actions on my GitHub Page (easy)&lt;/li&gt;
&lt;li&gt;Consume data using Contentful on my Github Page (Hard as F***)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That sounds like a piece of cake, sounds like a that simple task, popped into the Jira to change the color of the button - EASY - right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Reality
&lt;/h2&gt;

&lt;p&gt;When working at big companies — or companies that have an SRE/DevOps team allocated in the development workflow, in delivery part of the system — we start to become dangerously comfortable with our environment. Whatever deployment problem we have, we just open a ticket, assign it to the infrastructure team, and it's magically solved. We start to not care about the most important part of our development circle: &lt;strong&gt;the delivery&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Most of the time, we don't have to set up an entire pipeline from scratch because they're already there — battle-tested, documented, and stable for our use cases. Infrastructure as code? Someone else wrote it. CI/CD pipelines? Pre-configured and ready to use. Environment variable management? There's a corporate tool for that, and someone from platform engineering already set it up.&lt;/p&gt;

&lt;p&gt;This comfort creates a dangerous illusion of competence. We know how to use Jenkins, but do we know how to configure it from scratch? We can deploy to Kubernetes, but can we set up the cluster? We understand the application code, but the delivery mechanism becomes a black box that "just works."&lt;/p&gt;

&lt;p&gt;It's like being a chef who's only ever worked in a fully-equipped professional kitchen with prep cooks, sous chefs, and specialized equipment. Everything is where you expect it, ingredients are pre-prepared, and if the oven breaks, you call maintenance. Then one day, you try to cook a simple meal in a basic home kitchen. Suddenly, you realize you don't know where anything is, how the oven works, or even how to properly sharpen a knife.&lt;/p&gt;

&lt;p&gt;The scariest part? You don't realize how much you've forgotten until you're alone with a terminal, staring at a failed GitHub Action, wondering why something that should take 10 minutes is approaching hour three.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deployment Reality Check
&lt;/h2&gt;

&lt;p&gt;When we're using GitHub Actions, we have to understand two parts of the system and ecosystem.&lt;/p&gt;

&lt;p&gt;To deploy a GitHub Page, you have to choose between two approaches:&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 1: Build and Push to gh-pages Branch
&lt;/h3&gt;

&lt;p&gt;This is the "classic" approach where you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build your site locally or when automated in GitHub Actions&lt;/li&gt;
&lt;li&gt;Push the compiled/built files to a special gh-pages branch&lt;/li&gt;
&lt;li&gt;Let GitHub's built-in automation handle the actual deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy to GitHub Pages
on:
  push:
    branches: [ main ]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Setup Node
      uses: actions/setup-node@v2
      with:
        node-version: '18'

    - name: Install dependencies
      run: npm install

    - name: Build
      run: npm run build
      env:
        NEXT_PUBLIC_CONTENTFUL_SPACE_ID: ${{ secrets.CONTENTFUL_SPACE_ID }}
        NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN: ${{ secrets.CONTENTFUL_ACCESS_TOKEN }}

    - name: Deploy to gh-pages
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./out  # or ./dist, ./build - wherever your built files are
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub handles the web server configuration&lt;/li&gt;
&lt;li&gt;Simple deployment mechanism&lt;/li&gt;
&lt;li&gt;Clear separation between build and deploy&lt;/li&gt;
&lt;li&gt;Works great for static sites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less control over the deployment process&lt;/li&gt;
&lt;li&gt;Environment variables can be tricky during build time&lt;/li&gt;
&lt;li&gt;Another branch to manage (gh-pages)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Critical gotcha&lt;/em&gt;: Will fail silently if repository Pages settings aren't configured properly&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Approach 2: Custom GitHub Actions Deployment
&lt;/h3&gt;

&lt;p&gt;This approach gives you full control over both build and deployment, and is just remove all deploy part for Github work and back to our own pipeline work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy to GitHub Pages
on:
  push:
    branches: [ main ]

deployment
permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Setup Node
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        cache: 'npm'

    - name: Install dependencies
      run: npm install

    - name: Build
      run: npm run build
      env:
        NEXT_PUBLIC_CONTENTFUL_SPACE_ID: ${{ secrets.CONTENTFUL_SPACE_ID }}
        NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN: ${{ secrets.CONTENTFUL_ACCESS_TOKEN }}

    - name: Setup Pages
      uses: actions/configure-pages@v4

    - name: Upload artifact
      uses: actions/upload-pages-artifact@v3
      with:
        path: './out'  # your build output directory

    - name: Deploy to GitHub Pages
      id: deployment
      uses: actions/deploy-pages@v4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full control over the deployment process&lt;/li&gt;
&lt;li&gt;More modern approach (uses GitHub's newer Pages deployment API)&lt;/li&gt;
&lt;li&gt;Better integration with GitHub's security model&lt;/li&gt;
&lt;li&gt;No need for a separate gh-pages branch&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Which Approach Should You Choose?
&lt;/h3&gt;

&lt;p&gt;Go with Approach 1 (gh-pages) if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a simple build process&lt;/li&gt;
&lt;li&gt;You're comfortable with managing an extra branch&lt;/li&gt;
&lt;li&gt;You want the "battle-tested" method&lt;/li&gt;
&lt;li&gt;You're using older documentation or tutorials (many still reference this method)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go with Approach 2 (custom deployment) if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want the most up-to-date GitHub Pages experience&lt;/li&gt;
&lt;li&gt;You prefer not to manage a separate branch&lt;/li&gt;
&lt;li&gt;You need more control over the deployment process&lt;/li&gt;
&lt;li&gt;You're starting fresh (this is becoming the recommended approach)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Configuration Traps (And How to Avoid Them)
&lt;/h3&gt;

&lt;p&gt;Both approaches have their own "gotcha" moments that can turn your 10-minute deployment into a debugging marathon. Here's what the tutorials don't tell you:&lt;/p&gt;

&lt;p&gt;Approach 1: The Repository Settings Trap&lt;br&gt;
Your GitHub Action might run perfectly, push files to the gh-pages branch successfully, but your site still shows a 404. Why? You forgot to configure your repository's Pages settings.&lt;/p&gt;

&lt;p&gt;The solution:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your repository's Settings tab&lt;/li&gt;
&lt;li&gt;Scroll down to Pages in the left sidebar&lt;/li&gt;
&lt;li&gt;Under Source, select "Deploy from a branch"&lt;/li&gt;
&lt;li&gt;Choose gh-pages as the branch and / (root) as the folder&lt;/li&gt;
&lt;li&gt;Click Save&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without this configuration, GitHub doesn't know that your gh-pages branch contains your website. Your action succeeds, files get pushed, but nothing deploys.&lt;br&gt;
Approach 2: The Environment Declaration Trap&lt;br&gt;
As we discovered, missing environment: github-pages causes cryptic deployment token errors. But there's more to it:&lt;br&gt;
The complete solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  build:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The url part isn't strictly required, but it makes your deployment logs much more useful by showing you exactly where your site was deployed.&lt;/p&gt;

&lt;p&gt;The GITHUB_TOKEN Permissions Issue&lt;br&gt;
Both approaches can fail due to insufficient permissions. Make sure your workflow has the right permissions at the top:&lt;/p&gt;
&lt;h3&gt;
  
  
  For Approach 1
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;permissions:
  contents: write  # To push to gh-pages branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  For Approach 2
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;permissions:
  contents: read
  pages: write
  id-token: write
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Pro tip: If you're getting permission errors, double-check that Actions have write permissions in your repository settings under Settings → Actions → General → Workflow permissions.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Environment Variable Challenge
&lt;/h3&gt;

&lt;p&gt;Both approaches face the same fundamental challenge: how do you get API keys and secrets available during the build process?&lt;/p&gt;

&lt;p&gt;This is where my 3-hour debugging session began. The issue isn't GitHub Secrets (that part actually works great) — it's understanding how your build tool handles environment variables.&lt;/p&gt;

&lt;p&gt;The gotcha: Most modern frameworks (Vite, Next.js, Nuxt, etc.) have specific rules about which environment variables are available in the browser vs. the build process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This won't work in the browser (security risk)
CONTENTFUL_ACCESS_TOKEN=your_secret_token
# This works (Vite prefix)
VITE_CONTENTFUL_ACCESS_TOKEN=your_token
# This also works (Next.js prefix)
NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN=your_token
# And this (Nuxt prefix)
NUXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN=your_token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The build process needs to know which variables are safe to "bake into" your static files. Without the proper prefix, your bundler ignores the environment variable entirely — even though it's perfectly available in the GitHub Actions environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple Page, Complex Variables
&lt;/h3&gt;

&lt;p&gt;Here's where my "10-minute task" turned into a 3-hour debugging session.&lt;/p&gt;

&lt;p&gt;For a simple static page, approach #1 works beautifully. But the moment you introduce a headless CMS like Contentful, you need API keys. And API keys mean environment variables. And environment variables in GitHub Actions mean... well, let's just say it's not as straightforward as &lt;code&gt;import.meta.env.VITE_CONTENTFUL_API_KEY&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# What I thought would work
- name: Build
  run: npm run build
  env:
    CONTENTFUL_SPACE_ID: ${{ secrets.CONTENTFUL_SPACE_ID }}
    CONTENTFUL_ACCESS_TOKEN: ${{ secrets.CONTENTFUL_ACCESS_TOKEN }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, right? Wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Devil in the Details: GitHub Environments
&lt;/h3&gt;

&lt;p&gt;The problem isn't the GitHub Secrets part — that's actually straightforward once you know where to put them. The devil is in understanding that GitHub has two different concepts that sound similar but work completely differently:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Repository Secrets (the simple ones)&lt;/li&gt;
&lt;li&gt;Environment Secrets (the tricky ones)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Creating GitHub Environments
&lt;/h3&gt;

&lt;p&gt;Here's what the tutorials don't tell you: if you're using Approach 2 (custom deployment), you need to create a GitHub Environment first, then configure secrets within that environment.&lt;br&gt;
Step-by-step GitHub Environment setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your repository on GitHub&lt;/li&gt;
&lt;li&gt;Click Settings tab&lt;/li&gt;
&lt;li&gt;In the left sidebar, scroll down to Environments&lt;/li&gt;
&lt;li&gt;Click New Environment&lt;/li&gt;
&lt;li&gt;Name it github-pages (this exact name matters)&lt;/li&gt;
&lt;li&gt;Click Configure Environment&lt;/li&gt;
&lt;li&gt;Add your secrets here (not in the main repository secrets!)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  The Environment Declaration Trap
&lt;/h3&gt;

&lt;p&gt;In your GitHub Actions workflow, you must declare the environment explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  build:
    environment: github-pages  # Must match your environment name exactly
    runs-on: ubuntu-latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this breaks without warning: &lt;br&gt;
If you reference an environment that doesn't exist, GitHub Actions won't give you a clear error. Instead, you'll get cryptic messages like "deployment token not found" or permission errors that point you in completely wrong directions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Repository Secrets vs Environment Secrets
&lt;/h4&gt;

&lt;p&gt;This is where it gets confusing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository Secrets: Available to all workflows, accessed with ${{ secrets.SECRET_NAME }}&lt;/li&gt;
&lt;li&gt;Environment Secrets: Only available to jobs that declare the specific environment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you put your Contentful API keys in Repository Secrets but your workflow declares environment: github-pages, those secrets won't be available unless you ALSO add them to the github-pages Environment Secrets.&lt;/p&gt;

&lt;p&gt;The solution: Choose one approach and stick with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Repository Secrets and don't declare an environment, OR&lt;/li&gt;
&lt;li&gt;Create an Environment and put all your secrets there&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most deployment failures happen because you mix the two approaches without realizing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Comfort Zone Problem
&lt;/h2&gt;

&lt;p&gt;This experience made me realize something important about our industry. When we work in well-established teams with dedicated DevOps support, we lose touch with the fundamentals. We become like passengers who never learned to drive — comfortable in the backseat but helpless when we need to take the wheel.&lt;/p&gt;

&lt;p&gt;The irony is that these "simple" deployment tasks are the foundation of everything we do. Yet somehow, they become the most frustrating obstacles when we step outside our comfort zones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned (The Hard Way)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Read the framework documentation thoroughly — especially the parts about environment variables and build-time vs. runtime behavior&lt;/li&gt;
&lt;li&gt;Test your deployment pipeline early — don't wait until the very end to figure out environment configuration&lt;/li&gt;
&lt;li&gt;Keep deployment skills sharp — even if your day job doesn't require them&lt;/li&gt;
&lt;li&gt;Remember that "simple" is relative — what's simple with a full DevOps team might not be simple solo&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Silver Lining
&lt;/h2&gt;

&lt;p&gt;Despite the frustration, there's something deeply satisfying about solving these problems yourself. When that deployment finally succeeds and your personal project goes live, it feels different than launching something through an enterprise pipeline. You own every piece of it.&lt;/p&gt;

&lt;p&gt;Plus, now I have a perfectly configured blog with dynamic content from Contentful. Was it worth the 3-hour detour for a prefix? Ask me again when I'm updating my resume without touching any code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Environment variables might seem like a trivial part of development, but they represent something bigger: the gap between enterprise comfort and independent problem-solving. The next time you're setting up a personal project and find yourself googling "how to deploy to GitHub Pages with environment variables," remember — you're not alone, and it's probably simpler than you think.&lt;/p&gt;

&lt;p&gt;"It's just not as simple as it should be."&lt;/p&gt;

&lt;p&gt;Have you fallen into the environment variable trap? Share your deployment horror stories in the comments — misery loves company, especially when it involves missing prefixes and 3 AM debugging sessions.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>github</category>
      <category>githubactions</category>
      <category>webdev</category>
    </item>
    <item>
      <title>When to Choose NoSQL over SQL: A Simple Use Case Primer</title>
      <dc:creator>João Victor Mazagão</dc:creator>
      <pubDate>Wed, 14 May 2025 16:28:15 +0000</pubDate>
      <link>https://dev.to/jmazagao/when-to-choose-nosql-over-sql-a-simple-use-case-primer-242l</link>
      <guid>https://dev.to/jmazagao/when-to-choose-nosql-over-sql-a-simple-use-case-primer-242l</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
When you need flexible schemas, massive horizontal scale, or to ingest high-velocity, unstructured data—think NoSQL. In this post, we’ll walk through a concrete example (IoT heartbeat data) to see why a document store can outperform a relational database.&lt;/p&gt;


&lt;h2&gt;
  
  
  Knowledge Base
&lt;/h2&gt;

&lt;p&gt;Relational databases have powered applications for decades and remain highly capable of solving nearly every kind of problem. However, they come with drawbacks and considerable complexity for certain use cases. They store data in a single structure—table rows.&lt;/p&gt;

&lt;p&gt;They excel at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ACID transactions&lt;/strong&gt; and data integrity. Reads and writes are &lt;strong&gt;A&lt;/strong&gt;tomic, &lt;strong&gt;C&lt;/strong&gt;onsistent, &lt;strong&gt;I&lt;/strong&gt;solated, and &lt;strong&gt;D&lt;/strong&gt;urable, keeping your data correct even in the event of failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Joins&lt;/strong&gt; across well-defined tables. When relational data must be merged, SQL efficiently combines results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mature tooling&lt;/strong&gt; and SQL querying. Decades of ecosystem support: robust GUIs, ORMs, migration tools, performance analyzers, and the standardized SQL language for complex queries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern workloads—IoT telemetry, user-generated content, session stores—often demand &lt;strong&gt;schema flexibility&lt;/strong&gt;, &lt;strong&gt;elastic scaling&lt;/strong&gt;, and the ingestion of &lt;strong&gt;semi-structured data&lt;/strong&gt;. That’s where NoSQL (document stores) shine.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Use Case: IoT Heartbeat Monitoring
&lt;/h2&gt;

&lt;p&gt;Imagine you’re building a sensor network that captures athletes’ heartbeat readings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each device sends a JSON payload every second:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deviceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sensor-42"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025-05-14T09:00:05Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"heartRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"battery"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Key considerations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Thousands of write requests per second.&lt;/li&gt;
&lt;li&gt;Occasional reads such as:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;What was the average heart rate for sensor 42?&lt;/li&gt;
&lt;li&gt;What is the current battery level?&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  SQL Approach
&lt;/h3&gt;

&lt;p&gt;A relational schema might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;readings&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;device_id&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;heart_rate&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;battery&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;heart_rate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;heart_rate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="k"&gt;CHECK&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;battery&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Robust schema validation ensures data always follows the same pattern.&lt;/li&gt;
&lt;li&gt;Transactions provide ACID guarantees for correctness.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Drawbacks&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding new fields (e.g., temperature) requires altering the schema, leading to potentially extensive migrations.&lt;/li&gt;
&lt;li&gt;Horizontal sharding is complex due to the heavy write workload.&lt;/li&gt;
&lt;li&gt;Inserts can become a bottleneck under bursty loads.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  NoSQL Approach (Document Store)
&lt;/h3&gt;

&lt;p&gt;With a document store, you store exactly the data you receive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add new fields without altering the schema—simply include them in the JSON.&lt;/li&gt;
&lt;li&gt;Easy horizontal scaling.&lt;/li&gt;
&lt;li&gt;High write throughput.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Common drawbacks&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Potential lack of consistency—even with transactions—and schema divergence can occur, though some databases now offer schema validation.&lt;/li&gt;
&lt;li&gt;Joins across collections are less powerful and can be slower than SQL joins.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  When to Choose a NoSQL Database
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Evolving schema:&lt;/strong&gt; Your data model changes frequently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-velocity or high-volume writes:&lt;/strong&gt; Sensor data, logs, clickstreams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geographically distributed scale:&lt;/strong&gt; You need to shard reads/writes across regions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unstructured or semi-structured data:&lt;/strong&gt; JSON, XML, nested arrays.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your application requires strict ACID guarantees across multiple tables, complex joins, or you have a stable, rigid schema, SQL is still the best choice.&lt;/p&gt;




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

&lt;p&gt;NoSQL isn’t “better” than SQL; it’s different. As software engineers, we must choose the right tool for the job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQL&lt;/strong&gt; for complex transactions, relational integrity, and stable schemas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NoSQL&lt;/strong&gt; for flexible, high-throughput, schema-light workloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our IoT heartbeat example, a document store lets you start quickly, evolve your data model, and handle bursts of sensor data without heavy migrations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Did you enjoy this primer? Let me know in the comments or follow me for more database deep dives!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>mongodb</category>
      <category>backend</category>
      <category>iot</category>
    </item>
  </channel>
</rss>
