<?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: Harsh Mangalam</title>
    <description>The latest articles on DEV Community by Harsh Mangalam (@harshmangalam).</description>
    <link>https://dev.to/harshmangalam</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F366422%2Fa0bc76cf-cd38-4683-a643-885599b4b6e1.PNG</url>
      <title>DEV Community: Harsh Mangalam</title>
      <link>https://dev.to/harshmangalam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harshmangalam"/>
    <language>en</language>
    <item>
      <title>UPI at Scale: Handling Millions of Payments</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Thu, 13 Aug 2026 06:18:12 +0000</pubDate>
      <link>https://dev.to/harshmangalam/upi-at-scale-handling-millions-of-payments-47ah</link>
      <guid>https://dev.to/harshmangalam/upi-at-scale-handling-millions-of-payments-47ah</guid>
      <description>&lt;p&gt;Imagine this:&lt;/p&gt;

&lt;p&gt;It's salary day.&lt;/p&gt;

&lt;p&gt;It's 2 PM.&lt;/p&gt;

&lt;p&gt;Millions of people across India suddenly open their UPI apps and start paying rent, sending money to family, paying credit-card bills, and shopping online.&lt;/p&gt;

&lt;p&gt;Now here's the system-design interview question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If millions of people make payments at almost exactly the same time, is every request hitting one central server? What prevents the entire payment system from freezing?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first glance, it sounds like a scaling problem.&lt;/p&gt;

&lt;p&gt;It isn't &lt;em&gt;just&lt;/em&gt; a scaling problem.&lt;/p&gt;

&lt;p&gt;It's a combination of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;horizontal scaling&lt;/li&gt;
&lt;li&gt;concurrency&lt;/li&gt;
&lt;li&gt;distributed systems&lt;/li&gt;
&lt;li&gt;database consistency&lt;/li&gt;
&lt;li&gt;retries&lt;/li&gt;
&lt;li&gt;idempotency&lt;/li&gt;
&lt;li&gt;backpressure&lt;/li&gt;
&lt;li&gt;failure isolation&lt;/li&gt;
&lt;li&gt;downstream bottlenecks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's what makes payment systems such an interesting system-design problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  First: Don't Imagine One Giant UPI Server
&lt;/h2&gt;

&lt;p&gt;A common mental model looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Millions of users
                    |
                    v
             +-------------+
             | UPI Server  |
             +-------------+
                    |
                    v
                  Bank
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that were literally true, we'd have a pretty serious problem.&lt;/p&gt;

&lt;p&gt;One machine cannot safely process the country's entire payment traffic.&lt;/p&gt;

&lt;p&gt;Instead, think about a distributed system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Users
                      |
                      v
              +---------------+
              | API / Gateway |
              +---------------+
                 /    |    \
                /     |     \
               v      v      v
             [S1]   [S2]   [S3]
               |      |      |
               +------+------+
                      |
                Payment Services
                      |
             +--------+--------+
             |                 |
          Bank A             Bank B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact implementation of a real payment network is much more complicated than this diagram, but this is the right &lt;strong&gt;system-design mental model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The important idea is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The system is distributed across many machines and participating institutions.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 1: The First Problem — Traffic Spikes
&lt;/h2&gt;

&lt;p&gt;Let's take a concrete example.&lt;/p&gt;

&lt;p&gt;You want to pay your landlord:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;₹25,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the same moment, millions of other people are doing something similar.&lt;/p&gt;

&lt;p&gt;Suddenly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Normal traffic:

100K requests/sec


Salary day:

████████████████████████
1M+ requests/sec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do we handle the additional traffic?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Naive Solution: One Powerful Server
&lt;/h2&gt;

&lt;p&gt;We could buy a massive machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              1M requests/sec
                     |
                     v
             +---------------+
             | HUGE SERVER   |
             | 256 CPU cores |
             | 2 TB RAM      |
             +---------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is called &lt;strong&gt;vertical scaling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Make the machine bigger.&lt;/p&gt;

&lt;p&gt;But there are limits.&lt;/p&gt;

&lt;p&gt;Eventually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CPU        → limit
Memory     → limit
Network    → limit
Connections → limit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there's an even bigger problem.&lt;/p&gt;

&lt;p&gt;If the server dies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              💥
               |
               v
        +-------------+
        | One Server  |
        +-------------+

               |
               v

          Entire system
             DOWN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a payment system, that's unacceptable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Solution: Horizontal Scaling
&lt;/h2&gt;

&lt;p&gt;Instead of making one machine enormous, add more machines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Requests
                       |
                       v
               +---------------+
               | Load Balancer |
               +---------------+
                 /     |     \
                /      |      \
               v       v       v
             [S1]    [S2]    [S3]
               |       |       |
             [S4]    [S5]    [S6]
               |       |       |
              ...     ...     ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If one server handles 20,000 requests/sec, and we need roughly 1 million:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1,000,000 / 20,000 ≈ 50 servers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can scale the application tier horizontally.&lt;/p&gt;

&lt;p&gt;Now if one server fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S1 💥

S2
S3
S4
S5
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traffic can be routed to healthy servers.&lt;/p&gt;

&lt;p&gt;This gives us our first reusable system-design pattern:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pattern #1: Horizontal Scaling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When request volume exceeds the capacity of one machine, distribute requests across many machines.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  But We've Created a New Problem
&lt;/h2&gt;

&lt;p&gt;Suppose two of your payments arrive simultaneously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment A:
Harsh → Landlord ₹25,000

Payment B:
Harsh → Amazon ₹20,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They might land on different servers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  Load Balancer
                   /          \
                  v            v
                [S1]          [S2]
                  |             |
                  +------?------+
                         |
                       Bank
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose Harsh has:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;₹30,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both servers read the balance at approximately the same time.&lt;/p&gt;

&lt;p&gt;Server 1 sees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;₹30,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Server 2 sees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;₹30,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S1:
₹30,000 - ₹25,000
= ₹5,000

S2:
₹30,000 - ₹20,000
= ₹10,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system has effectively allowed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;₹45,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to be spent from an account containing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;₹30,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a &lt;strong&gt;race condition&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And this is where payment-system design gets interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: We Need Atomic State Changes
&lt;/h2&gt;

&lt;p&gt;A payment isn't just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UPDATE balance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conceptually, we need something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Check balance
     ↓
Verify payment
     ↓
Debit sender
     ↓
Credit receiver
     ↓
Record transaction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The critical state transition must happen safely under concurrency.&lt;/p&gt;

&lt;p&gt;We need a guarantee that two competing operations cannot both incorrectly modify the same financial state.&lt;/p&gt;

&lt;p&gt;Depending on the architecture, this can involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;database transactions&lt;/li&gt;
&lt;li&gt;locking&lt;/li&gt;
&lt;li&gt;optimistic concurrency control&lt;/li&gt;
&lt;li&gt;serialization&lt;/li&gt;
&lt;li&gt;partition ownership&lt;/li&gt;
&lt;li&gt;carefully designed state machines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important interview lesson isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Use database locks."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Identify the shared mutable state and protect the critical transition.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 3: Now the Database Becomes the Bottleneck
&lt;/h2&gt;

&lt;p&gt;Let's say we've successfully scaled our application servers.&lt;/p&gt;

&lt;p&gt;We now have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Load Balancer
                         |
          +--------------+--------------+
          |              |              |
         S1             S2             S3
          |              |              |
          +--------------+--------------+
                         |
                         v
                   +-----------+
                   | Database  |
                   +-----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have 500 application servers.&lt;/p&gt;

&lt;p&gt;But one database.&lt;/p&gt;

&lt;p&gt;Now all those servers are fighting for the same resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;500 servers
     |
     |
     v
+-----------+
|    DB     |
|     💥    |
+-----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application tier scales.&lt;/p&gt;

&lt;p&gt;The database doesn't.&lt;/p&gt;

&lt;p&gt;This is a classic distributed-systems bottleneck:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The fastest part of your system doesn't matter if a slower shared dependency limits the entire system.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4: Partition the Work
&lt;/h2&gt;

&lt;p&gt;Instead of forcing everything through one database/resource, we can partition data and workload.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Payment Requests
                        |
                +-------+-------+
                |               |
                v               v
           Partition A     Partition B
                |               |
              DB-A            DB-B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The partitioning strategy could be based on something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;account ID
bank
customer ID
transaction domain
geographical region
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact choice depends on the system.&lt;/p&gt;

&lt;p&gt;This is generally called:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sharding / Partitioning&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reusable pattern is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pattern #2: Partition the bottleneck&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When one resource can't handle the workload, divide the workload into independent partitions.&lt;/p&gt;




&lt;h2&gt;
  
  
  But There's Another Problem
&lt;/h2&gt;

&lt;p&gt;Imagine our application servers are perfectly healthy.&lt;/p&gt;

&lt;p&gt;Our databases are perfectly healthy.&lt;/p&gt;

&lt;p&gt;But a downstream bank suddenly becomes overloaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Payment Services
                /       |       \
               v        v        v
             Bank A   Bank B   Bank C
                                |
                                v
                              💥
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our system can process millions of incoming requests.&lt;/p&gt;

&lt;p&gt;But the downstream dependency might only safely process a smaller amount.&lt;/p&gt;

&lt;p&gt;This gives us another fundamental principle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The capacity of a distributed system is constrained by its critical bottlenecks and dependencies.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can't solve a downstream bottleneck by simply adding more application servers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Backpressure
&lt;/h2&gt;

&lt;p&gt;Suppose a component can safely process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100K operations/sec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but we're receiving:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;300K operations/sec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we blindly forward everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;300K
 |
 v
[Processor]
 |
 💥
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, for work that is safe to process asynchronously, we can introduce a buffer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;300K requests
      |
      v
  +-------+
  | Queue |
  +-------+
      |
      | 100K/sec
      v
  +-----------+
  | Processor |
  +-----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The queue absorbs temporary bursts.&lt;/p&gt;

&lt;p&gt;This gives us:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pattern #3: Backpressure&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When producers can generate work faster than consumers can process it, slow down producers or buffer the work.&lt;/p&gt;

&lt;p&gt;This is where technologies such as Kafka or other messaging systems become useful.&lt;/p&gt;

&lt;p&gt;But notice the reasoning.&lt;/p&gt;

&lt;p&gt;We didn't start with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Let's use Kafka."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We started with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Our producer is faster than our consumer. We need buffering/backpressure."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Then&lt;/strong&gt; we choose a technology.&lt;/p&gt;




&lt;h2&gt;
  
  
  Can We Queue the Entire Payment?
&lt;/h2&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;This is an important interview trap.&lt;/p&gt;

&lt;p&gt;You shouldn't say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We'll just put every payment into Kafka."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Financial transactions have correctness and latency requirements.&lt;/p&gt;

&lt;p&gt;There is a difference between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Critical payment state transition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Side effects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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;Payment
  |
  +----&amp;gt; Update financial state
  |
  +----&amp;gt; Send notification
  |
  +----&amp;gt; Update analytics
  |
  +----&amp;gt; Generate receipt
  |
  +----&amp;gt; Update recommendation system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The financial state transition may require strict correctness.&lt;/p&gt;

&lt;p&gt;But sending:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"₹25,000 paid successfully"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to a notification service doesn't necessarily need to block the core transaction.&lt;/p&gt;

&lt;p&gt;Those side effects can often be asynchronous.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Now Imagine the Network Fails
&lt;/h2&gt;

&lt;p&gt;Here's where payment systems become really interesting.&lt;/p&gt;

&lt;p&gt;You press:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PAY ₹25,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request reaches the payment system.&lt;/p&gt;

&lt;p&gt;The money gets debited.&lt;/p&gt;

&lt;p&gt;But before the response reaches your phone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bank → 💥 network timeout 💥 → Phone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your app says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Okay, I'll try again."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So you press Pay again.&lt;/p&gt;

&lt;p&gt;Now the system receives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Payment #1
₹25,000

Payment #2
₹25,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the system treats both as new payments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your account
   |
   +-- ₹25,000
   |
   +-- ₹25,000
   |
   v
₹50,000 debited
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's obviously unacceptable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7: Idempotency
&lt;/h2&gt;

&lt;p&gt;We need the system to recognize:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This retry is actually the same payment."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the client/request can carry a unique identifier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;payment_id = ABC123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ABC123 → process payment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ABC123 → already processed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system returns the previous result rather than charging the user again.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
   |
   v
+----------------------+
| payment_id = ABC123  |
+----------------------+
          |
          v
    Already exists?
       /       \
     YES        NO
      |          |
      v          v
Return result  Process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;idempotency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And it is one of the most important concepts in distributed systems.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pattern #4: Idempotency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A retry of the same logical operation should not produce an additional side effect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You will see this pattern everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;payments&lt;/li&gt;
&lt;li&gt;order creation&lt;/li&gt;
&lt;li&gt;payment webhooks&lt;/li&gt;
&lt;li&gt;message processing&lt;/li&gt;
&lt;li&gt;API retries&lt;/li&gt;
&lt;li&gt;distributed jobs&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 8: Why Retries Are Dangerous
&lt;/h2&gt;

&lt;p&gt;Retries sound harmless:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request failed
      ↓
Retry
      ↓
Retry
      ↓
Retry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But imagine 1 million clients doing this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              1M requests
                   |
                failure
                   |
             +-----+-----+
             |           |
           retry       retry
             |           |
             +-----+-----+
                   |
                 retry
                   |
                   v
               💥💥💥
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A failing system can actually make itself &lt;strong&gt;more overloaded through retries&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is called a &lt;strong&gt;retry storm&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So production systems need things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;exponential backoff&lt;/li&gt;
&lt;li&gt;jitter&lt;/li&gt;
&lt;li&gt;retry limits&lt;/li&gt;
&lt;li&gt;timeouts&lt;/li&gt;
&lt;li&gt;circuit breakers&lt;/li&gt;
&lt;li&gt;idempotency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, each mechanism exists because a specific failure mode exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Picture
&lt;/h2&gt;

&lt;p&gt;At this point our system is evolving.&lt;/p&gt;

&lt;p&gt;We started with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 |
 v
Server
 |
 v
Bank
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And progressively discovered problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traffic spike
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                Load Balancer
               /     |      \
             S1      S2      S3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Shared state
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Multiple servers
      |
      v
Concurrency control
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Database bottleneck
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      |
  partition
   /      \
 DB-A    DB-B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Downstream overload
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Producer
   |
 Queue / Backpressure
   |
Consumer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Network failure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
   |
 timeout
   |
 retry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Retry duplication
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;payment_id
     |
idempotency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our architecture is now becoming:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         Users
                           |
                           v
                    +-------------+
                    |   Gateway   |
                    +-------------+
                           |
                    Load balancing
                           |
             +-------------+-------------+
             |             |             |
            S1            S2            S3
             |             |             |
             +-------------+-------------+
                           |
                    Payment Service
                           |
                    +------+------+
                    |             |
               Partition A   Partition B
                    |             |
                   DB-A          DB-B
                    |
             Critical transaction
                    |
              +-----+------+
              |            |
          Async work    Notifications
              |
            Queue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And around the entire system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;timeouts
retries
idempotency
rate limits
backpressure
monitoring
failure isolation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Most Important Lesson
&lt;/h2&gt;

&lt;p&gt;When you're asked:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Design a UPI-scale payment system."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don't start drawing 20 boxes.&lt;/p&gt;

&lt;p&gt;Start asking:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What's the workload?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Requests/sec?
Peak requests/sec?
Average transaction size?
Read/write ratio?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. What's the critical state?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Account balance
Transaction status
Payment ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Where is concurrency dangerous?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Two payments touching the same account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. What's the bottleneck?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application?
Database?
Network?
Downstream bank?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. What happens during failure?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Timeout
Crash
Duplicate request
Partial success
Network partition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. What happens when traffic suddenly increases?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scale
Buffer
Rate limit
Backpressure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. What happens when the client retries?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Idempotency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the real system-design thought process.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Reusable Pattern Library
&lt;/h2&gt;

&lt;p&gt;By solving this one problem, we've already learned several patterns.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One server can't handle traffic&lt;/td&gt;
&lt;td&gt;Horizontal scaling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared state modified concurrently&lt;/td&gt;
&lt;td&gt;Atomicity / concurrency control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One DB becomes bottleneck&lt;/td&gt;
&lt;td&gt;Sharding / partitioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Producer faster than consumer&lt;/td&gt;
&lt;td&gt;Queue / backpressure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request repeated after timeout&lt;/td&gt;
&lt;td&gt;Idempotency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependency becomes slow/unavailable&lt;/td&gt;
&lt;td&gt;Timeout / circuit breaker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Huge traffic spike&lt;/td&gt;
&lt;td&gt;Rate limiting / load shedding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Temporary downstream failure&lt;/td&gt;
&lt;td&gt;Retry + backoff&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And this is exactly how you should prepare for SDE-2 system design.&lt;/p&gt;

&lt;p&gt;Don't memorize architectures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memorize the problem → failure → pattern relationship.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  One Final Mental Model
&lt;/h2&gt;

&lt;p&gt;When you see:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Millions of requests arrive simultaneously."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Think:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 HUGE TRAFFIC
                      |
                      v
              Can one machine?
                   /     \
                 NO       YES
                 |
                 v
        Horizontal scaling
                 |
                 v
        What's shared?
                 |
                 v
        Concurrency problem?
                 |
                 v
        Protect state transition
                 |
                 v
        What's the bottleneck?
                 |
                 v
        Partition / scale
                 |
                 v
       What if dependency slows?
                 |
                 v
        Backpressure / queue
                 |
                 v
       What if request retries?
                 |
                 v
             Idempotency
                 |
                 v
          What if it fails?
                 |
                 v
       Timeout / retry / recovery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the mental model I'd want an SDE-2 candidate to have.&lt;/p&gt;

&lt;p&gt;The interesting part of this problem isn't &lt;strong&gt;"How does UPI handle 1,000+ crore transactions?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How do you build a distributed system where massive concurrency, partial failures, retries, and bottlenecks don't turn a single ₹25,000 payment into a financial disaster?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And once you understand that, you can reuse the same reasoning for &lt;strong&gt;Cloudflare rate limiting, ticket booking, food delivery, Uber, payment gateways, distributed job systems, and almost every large-scale backend system.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>backend</category>
      <category>interview</category>
      <category>beginners</category>
    </item>
    <item>
      <title>What Really Happens When 25 Lakh People Click “Book” at the Same Time?</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Wed, 12 Aug 2026 06:17:47 +0000</pubDate>
      <link>https://dev.to/harshmangalam/what-really-happens-when-25-lakh-people-click-book-at-the-same-time-4dl1</link>
      <guid>https://dev.to/harshmangalam/what-really-happens-when-25-lakh-people-click-book-at-the-same-time-4dl1</guid>
      <description>&lt;p&gt;Imagine this.&lt;/p&gt;

&lt;p&gt;Tatkal booking opens at &lt;strong&gt;10:00 AM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At exactly 10:00:00, around &lt;strong&gt;25 lakh people&lt;/strong&gt; click the &lt;strong&gt;Book Now&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;There are only &lt;strong&gt;4 seats left&lt;/strong&gt; in your coach.&lt;/p&gt;

&lt;p&gt;So the obvious question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How does the system decide which 4 people get the seats?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Is it literally first-come-first-served at the millisecond level?&lt;/p&gt;

&lt;p&gt;And what happens to the other 24,99,996 requests?&lt;/p&gt;

&lt;p&gt;This is a great system design problem because it teaches several important concepts at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;load balancing&lt;/li&gt;
&lt;li&gt;rate limiting&lt;/li&gt;
&lt;li&gt;stateless services&lt;/li&gt;
&lt;li&gt;race conditions&lt;/li&gt;
&lt;li&gt;atomic operations&lt;/li&gt;
&lt;li&gt;queues&lt;/li&gt;
&lt;li&gt;hot keys&lt;/li&gt;
&lt;li&gt;partitioning&lt;/li&gt;
&lt;li&gt;backpressure&lt;/li&gt;
&lt;li&gt;source of truth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s build the system slowly, one problem at a time.&lt;/p&gt;




&lt;h2&gt;
  
  
  First, forget the database
&lt;/h2&gt;

&lt;p&gt;A beginner might imagine the system like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;25 lakh users
      |
      v
   Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That would be a disaster.&lt;/p&gt;

&lt;p&gt;A real system usually has several layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
  |
  v
Internet
  |
  v
Edge / CDN / WAF
  |
  v
Load Balancer
  |
  v
API Servers
  |
  v
Booking Service
  |
  v
Inventory Service
  |
  v
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer exists because the simpler design eventually breaks.&lt;/p&gt;

&lt;p&gt;Let’s understand why.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Who actually clicked first?
&lt;/h2&gt;

&lt;p&gt;Suppose two users click:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User A clicks at 10:00:00.001
User B clicks at 10:00:00.009
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks like User A should win.&lt;/p&gt;

&lt;p&gt;But now include network latency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User A network latency = 100 ms
User B network latency = 20 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Their requests reach the booking system at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User A → 10:00:00.101
User B → 10:00:00.029
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;User B reaches the server first.&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The system usually cannot guarantee ordering based on the exact physical moment someone clicked.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The user's laptop is outside the system's control.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why not send the click timestamp?
&lt;/h2&gt;

&lt;p&gt;You might think the browser could send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"clicked_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10:00:00.001"&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;But clients cannot be trusted.&lt;/p&gt;

&lt;p&gt;A modified browser could simply send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"clicked_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"09:59:59.000"&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;So authoritative decisions should happen on the server.&lt;/p&gt;

&lt;p&gt;This is a useful rule far beyond ticket booking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Never trust the client for critical state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Price
Permissions
Wallet balance
Inventory
Seat availability
Booking status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. The first problem is not seats
&lt;/h2&gt;

&lt;p&gt;Before worrying about the 4 seats, there is a more immediate problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;25 lakh requests just arrived.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If all of them enter your backend, your servers may collapse before anyone gets a ticket.&lt;/p&gt;

&lt;p&gt;So the first layer protects the system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;25 lakh users
      |
      v
+----------------------+
| Edge / Cloudflare    |
|----------------------|
| Rate limiting        |
| DDoS protection      |
| Bot detection        |
| Traffic filtering    |
+----------+-----------+
           |
           v
        Backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is called &lt;strong&gt;admission control&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Admission control: don't accept unlimited work
&lt;/h2&gt;

&lt;p&gt;Imagine a nightclub with capacity for 500 people.&lt;/p&gt;

&lt;p&gt;There are 20,000 people waiting outside.&lt;/p&gt;

&lt;p&gt;You would not allow all 20,000 inside and then decide what to do.&lt;/p&gt;

&lt;p&gt;There is a bouncer.&lt;/p&gt;

&lt;p&gt;In distributed systems, the "bouncer" could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rate limiting
Bot protection
Concurrency limits
Queues
Load shedding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Protect expensive downstream systems by limiting how much work enters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This pattern appears everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;flash sales&lt;/li&gt;
&lt;li&gt;online exams&lt;/li&gt;
&lt;li&gt;ticket launches&lt;/li&gt;
&lt;li&gt;gaming events&lt;/li&gt;
&lt;li&gt;IPO applications&lt;/li&gt;
&lt;li&gt;payment systems&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Then comes the load balancer
&lt;/h2&gt;

&lt;p&gt;One server cannot handle millions of requests.&lt;/p&gt;

&lt;p&gt;So we run many API servers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                Load Balancer
                     |
        ---------------------------
        |            |            |
        v            v            v
      API-1        API-2        API-100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The load balancer spreads requests across them.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;horizontal scaling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of buying one giant server, we add more servers.&lt;/p&gt;

&lt;p&gt;If one server handles roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;5,000 requests/second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then 100 servers could theoretically handle around:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;500,000 requests/second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actual capacity depends on the workload, but the pattern is what matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. API servers should be stateless
&lt;/h2&gt;

&lt;p&gt;Here is an important mistake.&lt;/p&gt;

&lt;p&gt;Suppose API Server 1 stores this in memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;availableSeats = 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And API Server 2 also stores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;availableSeats = 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now both servers might independently sell those four seats.&lt;/p&gt;

&lt;p&gt;That is obviously wrong.&lt;/p&gt;

&lt;p&gt;So critical shared state should not live independently inside each API server.&lt;/p&gt;

&lt;p&gt;Instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API-1 -----\
API-2 ------\
API-3 -------&amp;gt; Shared Inventory Service
API-4 ------/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API servers are mostly &lt;strong&gt;stateless&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This makes scaling easier because any request can go to any server.&lt;/p&gt;

&lt;p&gt;If Server 27 crashes, the load balancer simply routes traffic elsewhere.&lt;/p&gt;

&lt;p&gt;A useful mental model is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stateless compute is easy to scale. Shared mutable state is where distributed systems become difficult.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6. Now we reach the real problem: race conditions
&lt;/h2&gt;

&lt;p&gt;Suppose only one seat remains.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;availableSeats = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two servers receive booking requests almost simultaneously.&lt;/p&gt;

&lt;p&gt;Server A does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;READ availableSeats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It sees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Server B also does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;READ availableSeats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also sees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both then say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;seat is available
book it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now one seat has been sold to two users.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;race condition&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The timeline looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Time →

Server A    READ seats = 1
Server B        READ seats = 1
Server A            WRITE seats = 0
Server B                WRITE seats = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both requests believed they succeeded.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. The fix: atomic operations
&lt;/h2&gt;

&lt;p&gt;The mistake above is that we did this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;READ
CHECK
WRITE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as separate steps.&lt;/p&gt;

&lt;p&gt;Instead, the check and update should behave like one indivisible operation.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IF seats &amp;gt; 0
THEN seats = seats - 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One database implementation 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;UPDATE&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;available_seats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;available_seats&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;train_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;available_seats&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="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose one seat remains.&lt;/p&gt;

&lt;p&gt;Request A executes first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Success.&lt;/p&gt;

&lt;p&gt;Request B executes next.&lt;/p&gt;

&lt;p&gt;The condition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;available_seats &amp;gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is false.&lt;/p&gt;

&lt;p&gt;So Request B fails.&lt;/p&gt;

&lt;p&gt;No overselling.&lt;/p&gt;

&lt;p&gt;This property is called &lt;strong&gt;atomicity&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Either the whole operation happens or none of it happens.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  8. Great, so let 25 lakh requests hit this SQL query?
&lt;/h2&gt;

&lt;p&gt;Not so fast.&lt;/p&gt;

&lt;p&gt;The query may be logically correct, but there is another problem.&lt;/p&gt;

&lt;p&gt;All 25 lakh users want the same resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;25 lakh requests
        |
        v
+----------------------+
| Train 12952          |
| Tatkal 3A            |
| available_seats = 4  |
+----------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single inventory record becomes extremely hot.&lt;/p&gt;

&lt;p&gt;This is called a:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hot row&lt;/li&gt;
&lt;li&gt;hot key&lt;/li&gt;
&lt;li&gt;hotspot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if you have 10,000 application servers, they may all eventually fight over the same inventory record.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10,000 API servers
        |
        v
 same inventory row
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This teaches an important lesson:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Scaling your application servers does not automatically scale shared state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You see the same problem in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;concert tickets&lt;/li&gt;
&lt;li&gt;Amazon flash sales&lt;/li&gt;
&lt;li&gt;limited sneaker drops&lt;/li&gt;
&lt;li&gt;coupon redemption&lt;/li&gt;
&lt;li&gt;wallet balances&lt;/li&gt;
&lt;li&gt;stock trading&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. Use a queue to absorb the burst
&lt;/h2&gt;

&lt;p&gt;Instead of directly hammering the inventory system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;25 lakh requests
       |
       v
Inventory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we can place a queue in front:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;25 lakh requests
       |
       v
+----------------+
| Booking Queue  |
+-------+--------+
        |
        v
     Workers
        |
        v
    Inventory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the huge incoming burst can be absorbed temporarily.&lt;/p&gt;

&lt;p&gt;Requests may enter the queue as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R1
R2
R3
R4
R5
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose four seats exist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R1 → seat → 3 left
R2 → seat → 2 left
R3 → seat → 1 left
R4 → seat → 0 left
R5 → sold out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important transformation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Huge uncontrolled concurrency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Controlled processing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  10. Why queues are useful
&lt;/h2&gt;

&lt;p&gt;Queues decouple two different rates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rate at which requests arrive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rate at which the backend can process requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without a queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traffic spike
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; DATABASE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traffic spike
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;

        |
        v

+----------------------+
|        Queue         |
| |||||||||||||||||||  |
+----------+-----------+
           |
           v

       Workers

----&amp;gt; ----&amp;gt; ----&amp;gt; Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is also a form of &lt;strong&gt;backpressure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The downstream system says, in effect:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I will process work at the speed I can safely handle.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  11. Should there be one global queue?
&lt;/h2&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;Imagine one queue for every booking in India.&lt;/p&gt;

&lt;p&gt;Then a Delhi–Mumbai booking could block a completely unrelated Chennai–Bengaluru booking.&lt;/p&gt;

&lt;p&gt;That wastes parallelism.&lt;/p&gt;

&lt;p&gt;Instead, we partition the work.&lt;/p&gt;

&lt;p&gt;A possible inventory key could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;train_id + journey_date + class + quota
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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;12952:2026-08-20:3A:TATKAL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All requests for the same inventory key should follow the same ordering path.&lt;/p&gt;

&lt;p&gt;Different trains can be processed independently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Train A → Partition 1 → Worker 1
Train B → Partition 2 → Worker 2
Train C → Partition 3 → Worker 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;partitioning&lt;/strong&gt; or &lt;strong&gt;sharding&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. The magic idea: serialize only conflicting work
&lt;/h2&gt;

&lt;p&gt;This is one of the most reusable ideas in system design.&lt;/p&gt;

&lt;p&gt;We do not need to serialize every booking in the country.&lt;/p&gt;

&lt;p&gt;We only need to serialize requests that compete for the same inventory.&lt;/p&gt;

&lt;p&gt;So instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Every booking
    |
    v
one global worker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we do something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Same train/date/class/quota
          |
          v
   ordered processing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while unrelated inventory runs in parallel.&lt;/p&gt;

&lt;p&gt;A good interview phrase is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Serialize operations per inventory key, not globally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That gives us both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Correctness
+
Parallelism
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  13. So which four people actually win?
&lt;/h2&gt;

&lt;p&gt;Now we can finally answer the original question.&lt;/p&gt;

&lt;p&gt;The system may create an authoritative order somewhere inside its infrastructure.&lt;/p&gt;

&lt;p&gt;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;User B → sequence 91821
User X → sequence 91822
User A → sequence 91823
User Z → sequence 91824
User P → sequence 91825
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are four seats.&lt;/p&gt;

&lt;p&gt;So:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;91821 → gets seat
91822 → gets seat
91823 → gets seat
91824 → gets seat
91825 → sold out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact real-world click ordering may be impossible to know perfectly.&lt;/p&gt;

&lt;p&gt;What matters is that the system defines one reliable ordering at a controlled point.&lt;/p&gt;

&lt;p&gt;This leads to a broader distributed systems idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sometimes we create an authoritative ordering instead of trying to discover the absolute real-world ordering.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  14. What happens to the other 24,99,996 requests?
&lt;/h2&gt;

&lt;p&gt;We ideally do &lt;strong&gt;not&lt;/strong&gt; let every losing request perform an expensive database transaction.&lt;/p&gt;

&lt;p&gt;Once the system confidently knows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inventory = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;future work can often be rejected earlier.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 |
 v
API
 |
 v
Queue
 |
 v
Worker
 |
 v
Database
 |
 v
Sold out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we may eventually do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 |
 v
Booking Service
 |
 v
Sold out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is called &lt;strong&gt;fail fast&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If an operation clearly cannot succeed, reject it as early and cheaply as possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This saves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU&lt;/li&gt;
&lt;li&gt;database connections&lt;/li&gt;
&lt;li&gt;queue capacity&lt;/li&gt;
&lt;li&gt;network calls&lt;/li&gt;
&lt;li&gt;locks&lt;/li&gt;
&lt;li&gt;memory&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  15. But be careful with caching
&lt;/h2&gt;

&lt;p&gt;Suppose we cache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tatkal inventory = SOLD OUT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is useful for fast rejection.&lt;/p&gt;

&lt;p&gt;But what happens if someone fails payment?&lt;/p&gt;

&lt;p&gt;The seat might become available again.&lt;/p&gt;

&lt;p&gt;So we need to distinguish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source of truth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A cache is fast, but it may be stale.&lt;/p&gt;

&lt;p&gt;The authoritative inventory system decides the truth.&lt;/p&gt;

&lt;p&gt;A good rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use caches to make the system faster, not to accidentally create a second source of truth.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  16. Booking is not the same as confirmation
&lt;/h2&gt;

&lt;p&gt;There is another important complication.&lt;/p&gt;

&lt;p&gt;Imagine four users get seats, but payment takes two minutes.&lt;/p&gt;

&lt;p&gt;Should those seats be permanently gone immediately?&lt;/p&gt;

&lt;p&gt;Usually you need a temporary reservation.&lt;/p&gt;

&lt;p&gt;The booking may move through states like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AVAILABLE
    |
    v
HELD
    |
    v
PAYMENT_PENDING
    |
    +-----------+
    |           |
    v           v
CONFIRMED     FAILED
                |
                v
            AVAILABLE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4 seats

A → held
B → held
C → held
D → held

available = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A payment succeeds → confirmed

B payment fails → seat released

C succeeds → confirmed

D times out → seat released
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This introduces several new system design topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TTLs&lt;/li&gt;
&lt;li&gt;reservation expiry&lt;/li&gt;
&lt;li&gt;state machines&lt;/li&gt;
&lt;li&gt;retries&lt;/li&gt;
&lt;li&gt;payment failures&lt;/li&gt;
&lt;li&gt;compensation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are natural follow-ups once the basic booking flow is correct.&lt;/p&gt;




&lt;h2&gt;
  
  
  17. Final high-level architecture
&lt;/h2&gt;

&lt;p&gt;Putting everything together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                       USERS
                         |
                         v
               +-------------------+
               | Edge / Cloudflare |
               |-------------------|
               | DDoS protection   |
               | Rate limiting     |
               | Bot detection     |
               +---------+---------+
                         |
                         v
               +-------------------+
               |   Load Balancer   |
               +---------+---------+
                         |
          +--------------+--------------+
          |              |              |
          v              v              v
       API-1           API-2          API-N
          \              |              /
           \             |             /
            +------------+------------+
                         |
                         v
               +-------------------+
               | Booking Service   |
               +---------+---------+
                         |
                         v
               +-------------------+
               | Booking Queue     |
               | partitioned by    |
               | inventory key     |
               +---------+---------+
                         |
             +-----------+-----------+
             |           |           |
             v           v           v
          Worker 1    Worker 2    Worker N
             |           |           |
             +-----------+-----------+
                         |
                         v
               +-------------------+
               | Inventory Service |
               +---------+---------+
                         |
                         v
               +-------------------+
               |    Database       |
               | Source of Truth   |
               +-------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  18. What did we actually learn?
&lt;/h2&gt;

&lt;p&gt;The interesting part is not memorizing the architecture.&lt;/p&gt;

&lt;p&gt;The important part is understanding &lt;strong&gt;why each component appeared&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Millions of incoming requests&lt;/td&gt;
&lt;td&gt;Horizontal scaling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend may collapse&lt;/td&gt;
&lt;td&gt;Admission control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bots generate unfair traffic&lt;/td&gt;
&lt;td&gt;Rate limiting / bot protection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Many API servers&lt;/td&gt;
&lt;td&gt;Stateless services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two users can get the same seat&lt;/td&gt;
&lt;td&gt;Atomicity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Millions hit the same inventory&lt;/td&gt;
&lt;td&gt;Hotspot recognition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Huge burst at 10 AM&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend slower than incoming traffic&lt;/td&gt;
&lt;td&gt;Backpressure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Independent trains should run separately&lt;/td&gt;
&lt;td&gt;Partitioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same inventory needs ordering&lt;/td&gt;
&lt;td&gt;Per-key serialization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inventory already exhausted&lt;/td&gt;
&lt;td&gt;Fail fast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeated reads are expensive&lt;/td&gt;
&lt;td&gt;Caching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System needs one correct answer&lt;/td&gt;
&lt;td&gt;Source of truth&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  19. The most important system design habit
&lt;/h2&gt;

&lt;p&gt;Do not start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;We need Kafka.
We need Redis.
We need Cassandra.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What problem do I have?
        |
        v
Why does it happen?
        |
        v
What is the simplest solution?
        |
        v
What breaks at scale?
        |
        v
What guarantee do I need?
        |
        v
Which system design pattern gives me that guarantee?
        |
        v
What new tradeoff did I introduce?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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;25 lakh requests
    ↓
backend overload
    ↓
admission control
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;traffic arrives faster than backend processes
    ↓
queue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;multiple servers update same seat
    ↓
race condition
    ↓
atomic operation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;everyone hits same inventory
    ↓
hotspot
    ↓
partition + serialize per key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That way, the architecture becomes a consequence of the problem instead of something you memorize.&lt;/p&gt;




&lt;h2&gt;
  
  
  20. The one sentence to remember
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The hard part is not receiving 25 lakh requests. The hard part is safely coordinating millions of concurrent requests around a tiny amount of shared mutable state.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once this idea makes sense, a lot of other systems start looking familiar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;concert ticketing&lt;/li&gt;
&lt;li&gt;hotel bookings&lt;/li&gt;
&lt;li&gt;airline seats&lt;/li&gt;
&lt;li&gt;flash sales&lt;/li&gt;
&lt;li&gt;stock trades&lt;/li&gt;
&lt;li&gt;wallet balances&lt;/li&gt;
&lt;li&gt;coupon redemption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The domain changes.&lt;/p&gt;

&lt;p&gt;The underlying system design patterns repeat.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>distributedsystems</category>
      <category>backend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Migrated a 61,000+ Line TypeScript Monorepo to Next.js 16.3 &amp; TypeScript 7 — The Results Surprised Me</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Thu, 06 Aug 2026 09:27:33 +0000</pubDate>
      <link>https://dev.to/harshmangalam/i-migrated-a-61000-line-typescript-monorepo-to-nextjs-163-typescript-7-the-results-2obl</link>
      <guid>https://dev.to/harshmangalam/i-migrated-a-61000-line-typescript-monorepo-to-nextjs-163-typescript-7-the-results-2obl</guid>
      <description>&lt;p&gt;Performance improvements in release notes are always nice to read, but I've learned to take them with a grain of salt.&lt;/p&gt;

&lt;p&gt;A benchmark on a small demo application rarely tells you how your production codebase will behave.&lt;/p&gt;

&lt;p&gt;So I decided to benchmark one of my own projects after upgrading from &lt;strong&gt;Next.js 16.1 + TypeScript 5.8&lt;/strong&gt; to &lt;strong&gt;Next.js 16.3 + TypeScript 7&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The repository isn't enormous by enterprise standards, but it's large enough to expose real-world bottlenecks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;~61,000 lines of TypeScript&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Turborepo monorepo&lt;/li&gt;
&lt;li&gt;Multiple applications and shared packages&lt;/li&gt;
&lt;li&gt;Bun as the package manager/runtime&lt;/li&gt;
&lt;li&gt;Next.js frontend&lt;/li&gt;
&lt;li&gt;Shared internal packages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I measured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cold type checking&lt;/li&gt;
&lt;li&gt;Cached type checking&lt;/li&gt;
&lt;li&gt;Development startup&lt;/li&gt;
&lt;li&gt;Production build&lt;/li&gt;
&lt;li&gt;Static page generation&lt;/li&gt;
&lt;li&gt;Build output size&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Upgrade Path
&lt;/h2&gt;

&lt;p&gt;One thing worth mentioning is that I couldn't jump directly to TypeScript 7.&lt;/p&gt;

&lt;p&gt;My starting point was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 16.1&lt;/li&gt;
&lt;li&gt;TypeScript 5.8&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since &lt;strong&gt;Next.js 16.1 doesn't support TypeScript 7&lt;/strong&gt;, I first upgraded Next.js to &lt;strong&gt;16.3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That migration was surprisingly smooth and required almost no code changes.&lt;/p&gt;

&lt;p&gt;Once that was complete, I upgraded the monorepo to &lt;strong&gt;TypeScript 7&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Current Ecosystem Caveat
&lt;/h2&gt;

&lt;p&gt;At the time of writing, &lt;strong&gt;typescript-eslint&lt;/strong&gt; still doesn't fully support TypeScript 7.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tsc&lt;/code&gt; uses TypeScript 7&lt;/li&gt;
&lt;li&gt;ESLint still performs its analysis using TypeScript 5.9&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not a blocker, but it's something to be aware of if you upgrade today.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark 1 — Type Checking
&lt;/h2&gt;

&lt;p&gt;Cold run before upgrading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun run typecheck

Tasks:    6 successful, 6 total
Cached:   0 cached
Time:     29.805s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After upgrading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun run typecheck

Tasks:    6 successful, 6 total
Cached:   0 cached
Time:     9.296s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TS 5.8&lt;/td&gt;
&lt;td&gt;29.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TS 7&lt;/td&gt;
&lt;td&gt;9.3s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's roughly a &lt;strong&gt;3.2× improvement&lt;/strong&gt; for a cold type check.&lt;/p&gt;

&lt;p&gt;For a repository of this size, that's a significant reduction in feedback time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark 2 — Turborepo Cache
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;259ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;114ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Already fast, but still noticeably quicker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark 3 — Development Startup
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun run dev

Ready &lt;span class="k"&gt;in &lt;/span&gt;888ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun run dev

Ready &lt;span class="k"&gt;in &lt;/span&gt;600ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not a massive difference, but enough to make restarting the dev server feel snappier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark 4 — Production Build
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;time &lt;/span&gt;bun run build

real    0m52.044s
user    3m51.673s
sys     0m13.184s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;time &lt;/span&gt;bun run build

real    0m22.752s
user    0m58.419s
sys     0m8.791s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Build Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Before&lt;/td&gt;
&lt;td&gt;52.0s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After&lt;/td&gt;
&lt;td&gt;22.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's approximately &lt;strong&gt;56% faster&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One interesting observation is the CPU time.&lt;/p&gt;

&lt;p&gt;The previous build consumed almost four minutes of user CPU time.&lt;/p&gt;

&lt;p&gt;After upgrading, that dropped to under one minute, suggesting the build process itself became considerably more efficient.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark 5 — Static Generation
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generating static pages (17/17) in 3.3s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generating static pages (17/17) in 3.2s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essentially unchanged.&lt;/p&gt;

&lt;p&gt;This suggests that most of the improvements came earlier in the build pipeline rather than during static page generation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark 6 — Output Size
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; .next

50M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; .next

50M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The build output remained identical.&lt;/p&gt;

&lt;p&gt;No regressions in generated artifacts.&lt;/p&gt;




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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cold typecheck&lt;/td&gt;
&lt;td&gt;29.8s&lt;/td&gt;
&lt;td&gt;9.3s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cached typecheck&lt;/td&gt;
&lt;td&gt;259ms&lt;/td&gt;
&lt;td&gt;114ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dev startup&lt;/td&gt;
&lt;td&gt;888ms&lt;/td&gt;
&lt;td&gt;600ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production build&lt;/td&gt;
&lt;td&gt;52.0s&lt;/td&gt;
&lt;td&gt;22.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static generation&lt;/td&gt;
&lt;td&gt;3.3s&lt;/td&gt;
&lt;td&gt;3.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;.next&lt;/code&gt; size&lt;/td&gt;
&lt;td&gt;50 MB&lt;/td&gt;
&lt;td&gt;50 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  My Observations
&lt;/h2&gt;

&lt;p&gt;A few things stood out during the migration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Next.js upgrade itself was uneventful.&lt;/li&gt;
&lt;li&gt;TypeScript 7 delivered the largest measurable improvement in day-to-day workflows.&lt;/li&gt;
&lt;li&gt;Production builds became dramatically faster.&lt;/li&gt;
&lt;li&gt;Output size remained unchanged.&lt;/li&gt;
&lt;li&gt;Turborepo caching continued to work flawlessly.&lt;/li&gt;
&lt;li&gt;The only missing piece today is full TypeScript 7 support in &lt;code&gt;typescript-eslint&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;I wasn't expecting a dramatic improvement.&lt;/p&gt;

&lt;p&gt;The biggest surprise was seeing a full monorepo type check drop from nearly &lt;strong&gt;30 seconds to just over 9 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Combined with a production build that finished in less than half the previous time, the upgrade noticeably improved the development experience without requiring significant application changes.&lt;/p&gt;

&lt;p&gt;If you're maintaining a medium or large TypeScript monorepo, it's worth running your own benchmarks after upgrading.&lt;/p&gt;

&lt;p&gt;Your numbers will differ, but the improvements may surprise you as much as they surprised me.&lt;/p&gt;




&lt;p&gt;Have you upgraded to TypeScript 7 yet? I'd be interested to hear how your build times compare.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>bunjs</category>
    </item>
    <item>
      <title>Your Go API Is Running—But Is It Healthy?</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Mon, 20 Jul 2026 07:08:11 +0000</pubDate>
      <link>https://dev.to/harshmangalam/your-go-api-is-running-but-is-it-healthy-2jgo</link>
      <guid>https://dev.to/harshmangalam/your-go-api-is-running-but-is-it-healthy-2jgo</guid>
      <description>&lt;p&gt;A Go server can start successfully and still be unable to handle real requests.&lt;/p&gt;

&lt;p&gt;The process may be running while PostgreSQL is down. The API is alive, but it cannot do its main job.&lt;/p&gt;

&lt;p&gt;That led me to a simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the server is running, is the application truly healthy?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is what I learned while building a useful health endpoint in Go.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a health endpoint?
&lt;/h2&gt;

&lt;p&gt;A health endpoint is a small HTTP endpoint, usually something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /health
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is mainly used by Docker, Kubernetes, load balancers, and monitoring tools. These systems call the endpoint and decide whether the application should receive traffic.&lt;/p&gt;

&lt;p&gt;Health checks are commonly split into three types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Liveness:&lt;/strong&gt; Is the application process running?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readiness:&lt;/strong&gt; Can the application handle traffic right now?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Startup:&lt;/strong&gt; Has the application finished starting?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A liveness check should be simple. Restarting the application will not fix a database outage.&lt;/p&gt;

&lt;p&gt;The endpoint in this post is closer to a &lt;strong&gt;readiness check&lt;/strong&gt; because it checks PostgreSQL. If the database is unavailable, the application keeps running but reports that it is not ready for traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decide what the response should look like
&lt;/h2&gt;

&lt;p&gt;I wanted the response to answer three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is the whole application healthy?&lt;/li&gt;
&lt;li&gt;Which dependency failed?&lt;/li&gt;
&lt;li&gt;How long did each check take?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That gave me these two structs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Status&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt;                 &lt;span class="s"&gt;`json:"status"`&lt;/span&gt;
    &lt;span class="n"&gt;Checks&lt;/span&gt;    &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;CheckResult&lt;/span&gt; &lt;span class="s"&gt;`json:"checks"`&lt;/span&gt;
    &lt;span class="n"&gt;Timestamp&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;              &lt;span class="s"&gt;`json:"timestamp"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;CheckResult&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Status&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"status"`&lt;/span&gt;
    &lt;span class="n"&gt;Error&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"error,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;DurationMS&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;  &lt;span class="s"&gt;`json:"duration_ms"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Healthy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"healthy"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JSON tags control the field names in the response. &lt;code&gt;omitempty&lt;/code&gt; hides the error field when there is no error. The small &lt;code&gt;Healthy&lt;/code&gt; method keeps the handler easy to read.&lt;/p&gt;

&lt;p&gt;When PostgreSQL is available, &lt;code&gt;/health&lt;/code&gt; returns &lt;code&gt;200 OK&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checks"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"duration_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&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;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;"2026-07-20T10:30:00Z"&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;When PostgreSQL is unavailable, it returns &lt;code&gt;503 Service Unavailable&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"unhealthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checks"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"down"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ping postgres: connection refused"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"duration_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&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;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;"2026-07-20T10:31:00Z"&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;The HTTP status is important. A tool should not need to read the JSON just to learn whether the application is ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give every dependency the same shape
&lt;/h2&gt;

&lt;p&gt;PostgreSQL may not be the only dependency forever. An API might later need Redis, Kafka, or another internal service.&lt;/p&gt;

&lt;p&gt;A small interface gives every health check the same shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Checker&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each checker provides a name for the response and returns an error when its dependency is unavailable.&lt;/p&gt;

&lt;p&gt;The PostgreSQL checker is small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;PostgresChecker&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgxpool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewPostgresChecker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgxpool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;PostgresChecker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;PostgresChecker&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;PostgresChecker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"postgres"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;PostgresChecker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ping postgres: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Ping&lt;/code&gt; asks the connection pool to contact PostgreSQL. We do not need a large SQL query. A health check should be fast, cheap, and safe to run often.&lt;/p&gt;

&lt;p&gt;Wrapping the error with &lt;code&gt;ping postgres&lt;/code&gt; adds useful context when something fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the checks safely
&lt;/h2&gt;

&lt;p&gt;The service has one job: run every checker and combine the results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;checkers&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Checker&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checkers&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="n"&gt;Checker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;checkers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;Checker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;checkers&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;),&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;The constructor accepts any number of checkers and stores a copy of the list. The service begins each request with a healthy response and an empty map for the individual results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Checks&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;CheckResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;checkers&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;Timestamp&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTC&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;For each checker, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creates a two-second timeout.&lt;/li&gt;
&lt;li&gt;Records the start time.&lt;/li&gt;
&lt;li&gt;Runs the check.&lt;/li&gt;
&lt;li&gt;Saves its status, error, and duration.&lt;/li&gt;
&lt;li&gt;Marks the whole response unhealthy if any check fails.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The important part looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;checkCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;started&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checkCtx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;CheckResult&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="s"&gt;"up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;DurationMS&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;started&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Milliseconds&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"down"&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&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;Without a timeout, one stuck dependency could make &lt;code&gt;/health&lt;/code&gt; wait forever.&lt;/p&gt;

&lt;p&gt;The timeout is based on the incoming request context. If the caller disconnects, Go can cancel the remaining work instead of continuing a request nobody is waiting for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why run checks concurrently?
&lt;/h2&gt;

&lt;p&gt;Imagine three dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PostgreSQL: 100 ms
Redis:      200 ms
Kafka:      300 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running them one after another takes about &lt;code&gt;600 ms&lt;/code&gt;. Running them together takes about &lt;code&gt;300 ms&lt;/code&gt;, which is close to the slowest check.&lt;/p&gt;

&lt;p&gt;The service starts one goroutine for each checker and uses a &lt;code&gt;sync.WaitGroup&lt;/code&gt; to wait for all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;checkers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checker&lt;/span&gt; &lt;span class="n"&gt;Checker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="c"&gt;// Run the check and build its result.&lt;/span&gt;
    &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goroutines write to the same response map, so a &lt;code&gt;sync.Mutex&lt;/code&gt; protects those writes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"unhealthy"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With only one dependency, concurrency does not make the endpoint faster. Its value appears when more checks are registered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn the result into HTTP
&lt;/h2&gt;

&lt;p&gt;The handler runs the service, selects the status code, and writes JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Healthy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusServiceUnavailable&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&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;Finally, the checker, service, and handler are connected in &lt;code&gt;main.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;postgresChecker&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewPostgresChecker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;healthService&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;postgresChecker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;healthService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One request now follows a clear path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /health
    -&amp;gt; handler
    -&amp;gt; health service
    -&amp;gt; dependency checkers
    -&amp;gt; JSON response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A few practical rules
&lt;/h2&gt;

&lt;p&gt;Health checks should stay lightweight. Avoid large queries, writes, or slow calls to external services.&lt;/p&gt;

&lt;p&gt;Health is also not the same as monitoring. A health endpoint answers, "Can this instance receive traffic?" Metrics, logs, and traces explain how the application performs and why failures happen.&lt;/p&gt;

&lt;p&gt;Be careful with error messages too. Detailed errors are helpful during development, but a public endpoint should not reveal passwords, connection strings, or other private information.&lt;/p&gt;

&lt;p&gt;For a small codebase, all of this can live in one &lt;code&gt;health.go&lt;/code&gt; file. Split it later when the file becomes harder to navigate, not simply because it might grow one day.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;A useful health endpoint is more than a hard-coded &lt;code&gt;{"status":"ok"}&lt;/code&gt; response.&lt;/p&gt;

&lt;p&gt;It needs clear output, correct HTTP status codes, fast dependency checks, timeouts, and safe handling of multiple checks. It should also know its limit: health tells us whether the application is ready, while monitoring tells us what is happening over time.&lt;/p&gt;

&lt;p&gt;It is a small feature, but it makes an API much easier to operate and trust.&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>backend</category>
      <category>api</category>
    </item>
    <item>
      <title>From http.ServeMux to Dependency Injection in Go: A Beginner-Friendly Guide</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Fri, 17 Jul 2026 07:29:15 +0000</pubDate>
      <link>https://dev.to/harshmangalam/from-httpservemux-to-dependency-injection-in-go-a-beginner-friendly-guide-3kc3</link>
      <guid>https://dev.to/harshmangalam/from-httpservemux-to-dependency-injection-in-go-a-beginner-friendly-guide-3kc3</guid>
      <description>&lt;p&gt;When I first saw code like this, it felt as if too many things were happening in one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;healthService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is a &lt;code&gt;mux&lt;/code&gt;? Why are we giving it a handler? How does the handler get the service? Who calls &lt;code&gt;ServeHTTP&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;This article answers those questions by starting with the smallest possible Go HTTP server and building toward a clean handler-and-service design one step at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The big idea
&lt;/h2&gt;

&lt;p&gt;An HTTP request moves through the application like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /health
     │
     ▼
HTTP server
     │
     ▼
ServeMux
     │
     ▼
Health handler
     │
     ▼
Health service
     │
     ▼
Dependency checker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each part has one job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The HTTP server receives requests.&lt;/li&gt;
&lt;li&gt;The mux decides which handler should receive each request.&lt;/li&gt;
&lt;li&gt;The handler translates between HTTP and our application.&lt;/li&gt;
&lt;li&gt;The service performs the application logic.&lt;/li&gt;
&lt;li&gt;A checker knows how to inspect one dependency, such as PostgreSQL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let us build this structure gradually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: The smallest useful mux and handler
&lt;/h2&gt;

&lt;p&gt;Go provides an HTTP router called &lt;code&gt;http.ServeMux&lt;/code&gt;. A router matches an incoming request with the code that should handle it.&lt;/p&gt;

&lt;p&gt;The method-and-path pattern used below, such as &lt;code&gt;"GET /health"&lt;/code&gt;, requires Go 1.22 or newer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&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;There are three important lines here.&lt;/p&gt;

&lt;p&gt;First, we create a mux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, we register a function for &lt;code&gt;GET /health&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"healthy"&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;This tells the mux:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a &lt;code&gt;GET /health&lt;/code&gt; request arrives, run this function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, we start the server and give it the mux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server receives requests, but the mux decides where they go.&lt;/p&gt;

&lt;p&gt;If we run the program and send this request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we receive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;healthy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Give the handler function a name
&lt;/h2&gt;

&lt;p&gt;An anonymous function is convenient, but it becomes harder to read as it grows. We can move it into a named function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;healthHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;healthHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&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;Notice that we pass the function itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;healthHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We do not call it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Wrong: this tries to call the function immediately.&lt;/span&gt;
&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;healthHandler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mux saves the function and calls it later when a matching request arrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Introduce a service
&lt;/h2&gt;

&lt;p&gt;Returning a fixed string does not require application logic. A real health endpoint may need to inspect PostgreSQL, Redis, or other dependencies.&lt;/p&gt;

&lt;p&gt;We can put that logic in a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HealthService&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HealthService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"healthy"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For now, this service still returns a fixed value. That is okay—we are focusing on how the pieces connect.&lt;/p&gt;

&lt;p&gt;One easy way to let the handler use the service is with a closure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;HealthService&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&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;The handler can use &lt;code&gt;service&lt;/code&gt; because the function was created in the same surrounding scope.&lt;/p&gt;

&lt;p&gt;The request now follows this path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /health → mux → handler function → service.Status()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a good solution for a small program.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Let a handler struct remember the service
&lt;/h2&gt;

&lt;p&gt;As an application grows, a handler may need several methods or dependencies. A struct gives us a clear place to store them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HealthHandler&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HealthService&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;service&lt;/code&gt; field means every &lt;code&gt;HealthHandler&lt;/code&gt; value remembers which health service it should use.&lt;/p&gt;

&lt;p&gt;We create the handler with a constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewHealthHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HealthService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HealthHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;HealthHandler&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&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;Passing a dependency into an object from the outside is called &lt;strong&gt;dependency injection&lt;/strong&gt;. Despite the intimidating name, the idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create a value, then give it the things it needs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The handler does not create its own service. &lt;code&gt;main&lt;/code&gt; creates the service and passes it in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Understand the &lt;code&gt;http.Handler&lt;/code&gt; interface
&lt;/h2&gt;

&lt;p&gt;The standard library defines an interface that is approximately this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Request&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;Any type with a matching &lt;code&gt;ServeHTTP&lt;/code&gt; method can act as an HTTP handler.&lt;/p&gt;

&lt;p&gt;We can make our &lt;code&gt;HealthHandler&lt;/code&gt; satisfy that interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HealthHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&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;We do not need to write &lt;code&gt;implements http.Handler&lt;/code&gt;. Go recognizes automatically that &lt;code&gt;*HealthHandler&lt;/code&gt; has the required method.&lt;/p&gt;

&lt;p&gt;Now we can register it with &lt;code&gt;mux.Handle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;HealthService&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHealthHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&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;When a matching request arrives, the mux effectively calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We do not call &lt;code&gt;ServeHTTP&lt;/code&gt; ourselves. The standard library does it for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;HandleFunc&lt;/code&gt; versus &lt;code&gt;Handle&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;These two methods are similar, so they are easy to confuse.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;HandleFunc&lt;/code&gt; when you have a function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"healthy"&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;Use &lt;code&gt;Handle&lt;/code&gt; when you have a value that implements &lt;code&gt;http.Handler&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHealthHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A useful shortcut is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function                         → HandleFunc
value with a ServeHTTP method    → Handle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Applying this to a real health-check package
&lt;/h2&gt;

&lt;p&gt;Now let us return to the original line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;healthService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It becomes easier to understand if we expand it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;healthHandler&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;healthService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;healthHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The constructor stores the service inside the handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&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;The handler uses that stored service when a request arrives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="n"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Healthy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusServiceUnavailable&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&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;The handler has a narrow responsibility:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ask the service for the current health result.&lt;/li&gt;
&lt;li&gt;Choose the correct HTTP status code.&lt;/li&gt;
&lt;li&gt;Encode the result as JSON.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It does not know how PostgreSQL is checked. That responsibility belongs elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring the complete application
&lt;/h2&gt;

&lt;p&gt;The clearest way to read the application wiring is one layer at a time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewPostgres&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"initialize postgres: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;postgresChecker&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewPostgresChecker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;healthService&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;postgresChecker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;healthHandler&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;healthService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;healthHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each line gives one object to the next:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PostgreSQL pool
      │
      ▼
PostgreSQL checker
      │
      ▼
Health service
      │
      ▼
Health handler
      │
      ▼
ServeMux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shorter version is equivalent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;healthService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expanded version is often easier to learn and debug. The shorter version is only a convenience; it is not a different design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow one request from beginning to end
&lt;/h2&gt;

&lt;p&gt;Suppose we run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The HTTP server receives &lt;code&gt;GET /health&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The server passes the request to the mux.&lt;/li&gt;
&lt;li&gt;The mux finds the handler registered for &lt;code&gt;GET /health&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The mux calls &lt;code&gt;healthHandler.ServeHTTP(w, r)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The handler calls &lt;code&gt;healthService.Check(r.Context())&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The service runs its registered dependency checkers.&lt;/li&gt;
&lt;li&gt;The PostgreSQL checker calls &lt;code&gt;pool.Ping(ctx)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The result returns through the service and handler.&lt;/li&gt;
&lt;li&gt;The handler sends JSON and either &lt;code&gt;200 OK&lt;/code&gt; or &lt;code&gt;503 Service Unavailable&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The dependencies are created from bottom to top during startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pool → checker → service → handler → mux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request travels from top to bottom at runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mux → handler → service → checker → pool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seeing those as two separate moments—application startup and request handling—usually removes much of the confusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why keep the service and handler separate?
&lt;/h2&gt;

&lt;p&gt;We could put everything inside one handler function. That might be fine for a tiny experiment, but separating them gives us useful boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The handler deals with HTTP concepts such as request contexts, JSON, and status codes.&lt;/li&gt;
&lt;li&gt;The service coordinates health checks and decides whether the application is healthy.&lt;/li&gt;
&lt;li&gt;Each checker understands one external dependency.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main&lt;/code&gt; creates and connects the components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This also makes future changes local. Adding Redis does not require changing the handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;healthService&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;postgresChecker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;redisChecker&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;The handler still asks the same service the same question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common beginner misunderstandings
&lt;/h2&gt;

&lt;h3&gt;
  
  
  “Does the mux execute the handler during startup?”
&lt;/h3&gt;

&lt;p&gt;No. Registering a handler only saves it for later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;healthHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It executes after a matching request arrives.&lt;/p&gt;

&lt;h3&gt;
  
  
  “Why do we not call &lt;code&gt;ServeHTTP&lt;/code&gt;?”
&lt;/h3&gt;

&lt;p&gt;The HTTP server and mux call it. Our responsibility is to provide a value with the correct method.&lt;/p&gt;

&lt;h3&gt;
  
  
  “Is &lt;code&gt;NewHandler&lt;/code&gt; special Go syntax?”
&lt;/h3&gt;

&lt;p&gt;No. It is an ordinary function following a common naming convention for constructors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  “Does the mux know about the service?”
&lt;/h3&gt;

&lt;p&gt;No. The mux knows only about the handler. The handler knows about the service because the service was injected into it.&lt;/p&gt;

&lt;h3&gt;
  
  
  “Why use a pointer such as &lt;code&gt;*Handler&lt;/code&gt;?”
&lt;/h3&gt;

&lt;p&gt;The pointer lets the handler methods work with the same handler value and its stored dependencies without copying the struct. This is the usual pattern for stateful handlers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final mental model
&lt;/h2&gt;

&lt;p&gt;If you remember only five ideas, remember these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;http.Server&lt;/code&gt; receives HTTP requests.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;http.ServeMux&lt;/code&gt; chooses a handler based on the request path and method.&lt;/li&gt;
&lt;li&gt;A type becomes an &lt;code&gt;http.Handler&lt;/code&gt; by defining &lt;code&gt;ServeHTTP&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A handler can store a service in a struct field.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main&lt;/code&gt; creates the dependencies and connects them together.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The line that once looked complicated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /health"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;healthService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now reads naturally:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create a health handler that uses this health service, then register it for &lt;code&gt;GET /health&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the core of mux, handlers, and dependency injection in Go.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>beginners</category>
      <category>go</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How Next.js Image Optimization Works Under the Hood</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Thu, 16 Jul 2026 06:39:54 +0000</pubDate>
      <link>https://dev.to/harshmangalam/how-nextjs-image-optimization-works-under-the-hood-55lf</link>
      <guid>https://dev.to/harshmangalam/how-nextjs-image-optimization-works-under-the-hood-55lf</guid>
      <description>&lt;p&gt;When I first started using Next.js, I replaced every &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;Image /&amp;gt;&lt;/code&gt; because the documentation said it was "optimized."&lt;/p&gt;

&lt;p&gt;It worked.&lt;/p&gt;

&lt;p&gt;But I had one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is it actually doing behind the scenes?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After digging into it, I realized the idea is much simpler than I expected.&lt;/p&gt;

&lt;p&gt;Let's walk through it together.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem with a normal &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Imagine you have a beautiful travel photo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;taj-mahal.png
4000 × 3000
6 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You display it on your website like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/taj-mahal.png"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When someone opens your page, the browser asks the server for that image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser
   │
   ▼
GET /taj-mahal.png
   │
   ▼
Server sends 6 MB image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser downloads the entire file.&lt;/p&gt;

&lt;p&gt;Now imagine your image is only shown inside a small card that's &lt;strong&gt;300 pixels wide&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The browser still downloads the full &lt;strong&gt;4000-pixel&lt;/strong&gt; image.&lt;/p&gt;

&lt;p&gt;That means you're downloading way more data than you actually need.&lt;/p&gt;




&lt;h2&gt;
  
  
  What would be the smarter approach?
&lt;/h2&gt;

&lt;p&gt;Instead of sending the same image to everyone, what if we could do this?&lt;/p&gt;

&lt;p&gt;For phones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;300 px image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For tablets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;600 px image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For desktops:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1000 px image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everyone sees the same picture, but only downloads the size they actually need.&lt;/p&gt;

&lt;p&gt;That is the main idea behind image optimization.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enter Next.js &lt;code&gt;&amp;lt;Image /&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of writing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/taj-mahal.png"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/taj-mahal.png"&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks almost the same.&lt;br&gt;
But behind the scenes, something very different happens.&lt;/p&gt;


&lt;h2&gt;
  
  
  The first surprise
&lt;/h2&gt;

&lt;p&gt;You might think the browser requests this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /taj-mahal.png
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't.&lt;/p&gt;

&lt;p&gt;Instead, it requests something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /_next/image?url=/taj-mahal.png&amp;amp;w=640&amp;amp;q=75
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, this looked strange to me.&lt;/p&gt;

&lt;p&gt;Why isn't it requesting the actual image?&lt;/p&gt;




&lt;h2&gt;
  
  
  Meet the Image Optimizer
&lt;/h2&gt;

&lt;p&gt;That &lt;code&gt;/_next/image&lt;/code&gt; URL is a special endpoint created by Next.js.&lt;/p&gt;

&lt;p&gt;Instead of sending the original image directly, the request goes through the optimizer first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser
    │
    ▼
Next.js Image Optimizer
    │
    ▼
Original Image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can think of it as a smart middleman.&lt;/p&gt;

&lt;p&gt;Before giving the browser the image, it asks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What size do you need?&lt;/li&gt;
&lt;li&gt;What quality should I use?&lt;/li&gt;
&lt;li&gt;Which image format does your browser support?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then it prepares the best version.&lt;/p&gt;




&lt;h2&gt;
  
  
  What happens when the request arrives?
&lt;/h2&gt;

&lt;p&gt;Suppose the browser sends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /_next/image?url=/taj-mahal.png&amp;amp;w=640&amp;amp;q=75
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next.js now knows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Original image location&lt;/li&gt;
&lt;li&gt;Required width (640px)&lt;/li&gt;
&lt;li&gt;Image quality (75)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the real work begins.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 — Load the original image
&lt;/h2&gt;

&lt;p&gt;Next.js finds the original image.&lt;/p&gt;

&lt;p&gt;It might come from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your &lt;code&gt;public&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;an external URL&lt;/li&gt;
&lt;li&gt;cloud storage like S3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The optimizer first loads the original image into memory.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2 — Resize it
&lt;/h2&gt;

&lt;p&gt;Suppose the original image is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4000 px wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the browser only needs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;640 px
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no reason to send all 4000 pixels.&lt;/p&gt;

&lt;p&gt;Next.js resizes the image to the requested width.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4000 px

↓

640 px
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This alone saves a lot of bandwidth.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Compress it
&lt;/h2&gt;

&lt;p&gt;Even after resizing, the image can often be made much smaller.&lt;/p&gt;

&lt;p&gt;If the quality is set to &lt;code&gt;75&lt;/code&gt;, Next.js compresses it while trying to keep it looking almost identical.&lt;/p&gt;

&lt;p&gt;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;400 KB

↓

90 KB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user usually can't notice the difference, but their internet connection definitely can.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4 — Choose a better format
&lt;/h2&gt;

&lt;p&gt;Modern browsers support formats like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebP&lt;/li&gt;
&lt;li&gt;AVIF&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These formats are usually much smaller than PNG or JPEG.&lt;/p&gt;

&lt;p&gt;When your browser makes a request, it also sends an &lt;code&gt;Accept&lt;/code&gt; header that tells the server which image formats it understands.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Accept: image/avif,image/webp,image/*,*/*
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the browser supports WebP or AVIF, Next.js may convert the original PNG or JPEG into one of those formats before sending it back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Original

PNG

↓

Optimized

WebP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The picture looks almost identical but downloads much faster.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5 — Cache the result
&lt;/h2&gt;

&lt;p&gt;Image optimization isn't free.&lt;/p&gt;

&lt;p&gt;Resizing and compressing images takes CPU time.&lt;/p&gt;

&lt;p&gt;So Next.js stores the optimized version.&lt;/p&gt;

&lt;p&gt;The first request looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser

↓

Next.js

↓

Resize

↓

Compress

↓

Cache

↓

Send image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second request becomes much simpler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser

↓

Next.js

↓

Cache

↓

Send image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No resizing.&lt;/p&gt;

&lt;p&gt;No compression.&lt;/p&gt;

&lt;p&gt;Just return the cached image.&lt;/p&gt;




&lt;h2&gt;
  
  
  How does the browser know which size to download?
&lt;/h2&gt;

&lt;p&gt;This part surprised me the most.&lt;/p&gt;

&lt;p&gt;Next.js doesn't generate just one image.&lt;/p&gt;

&lt;p&gt;It generates multiple versions.&lt;/p&gt;

&lt;p&gt;Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;320 px

640 px

750 px

1080 px

1920 px
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It then generates an HTML &lt;code&gt;srcset&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Something similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/_next/image?url=/taj-mahal.png&amp;amp;w=640&amp;amp;q=75"&lt;/span&gt;
  &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"
    /_next/image?url=/taj-mahal.png&amp;amp;w=320&amp;amp;q=75 320w,
    /_next/image?url=/taj-mahal.png&amp;amp;w=640&amp;amp;q=75 640w,
    /_next/image?url=/taj-mahal.png&amp;amp;w=1080&amp;amp;q=75 1080w
  "&lt;/span&gt;
  &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"100vw"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now here's the interesting part.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next.js doesn't decide which image gets downloaded.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;browser&lt;/strong&gt; does.&lt;/p&gt;

&lt;p&gt;If you're on a phone, it might download the 640px version.&lt;/p&gt;

&lt;p&gt;If you're on a desktop with a Retina display, it might choose the 1080px version.&lt;/p&gt;

&lt;p&gt;The browser looks at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Viewport size&lt;/li&gt;
&lt;li&gt;Device pixel ratio (Retina, 2x, 3x, etc.)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;sizes&lt;/code&gt; attribute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then it picks the most appropriate image.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why do we provide &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;One more nice feature.&lt;/p&gt;

&lt;p&gt;When you write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the browser already knows how much space the image will take.&lt;/p&gt;

&lt;p&gt;Even before the image finishes downloading.&lt;/p&gt;

&lt;p&gt;That means your page doesn't suddenly jump around while loading.&lt;/p&gt;

&lt;p&gt;Without dimensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Header

Text

(Image loads)

Everything moves down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With dimensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Header

[Reserved Image Space]

Text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything stays stable.&lt;/p&gt;

&lt;p&gt;This improves a Core Web Vitals metric called &lt;strong&gt;Cumulative Layout Shift (CLS)&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Putting everything together
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="err"&gt;│&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;

&lt;span class="nx"&gt;Browser&lt;/span&gt; &lt;span class="nx"&gt;requests&lt;/span&gt;

&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;_next&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;

      &lt;span class="err"&gt;│&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;

&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt; &lt;span class="nx"&gt;loads&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt;

      &lt;span class="err"&gt;│&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;

&lt;span class="nx"&gt;Resize&lt;/span&gt;

      &lt;span class="err"&gt;│&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;

&lt;span class="nx"&gt;Compress&lt;/span&gt;

      &lt;span class="err"&gt;│&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;

&lt;span class="nx"&gt;Convert&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;WebP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nc"&gt;AVIF &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="err"&gt;│&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;

&lt;span class="nx"&gt;Store&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;

      &lt;span class="err"&gt;│&lt;/span&gt;
      &lt;span class="err"&gt;▼&lt;/span&gt;

&lt;span class="nx"&gt;Send&lt;/span&gt; &lt;span class="nx"&gt;optimized&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Before learning this, I thought &lt;code&gt;&amp;lt;Image /&amp;gt;&lt;/code&gt; was just another React component.&lt;/p&gt;

&lt;p&gt;It turns out it's much more than that.&lt;/p&gt;

&lt;p&gt;It's an image optimization pipeline built into Next.js.&lt;/p&gt;

&lt;p&gt;Instead of sending every visitor the same large image, it creates a version that's appropriate for their device, browser, and screen size.&lt;/p&gt;

&lt;p&gt;As developers, we only write one component.&lt;/p&gt;

&lt;p&gt;Behind the scenes, Next.js handles resizing, compression, modern image formats, caching, and responsive images for us.&lt;/p&gt;

&lt;p&gt;That's a lot of work hidden behind a single line of code.&lt;/p&gt;




&lt;p&gt;If you enjoyed this article, the next logical step is understanding &lt;strong&gt;how &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; actually work&lt;/strong&gt;. That's where the browser starts making intelligent decisions about which image to download, and it's one of the coolest parts of responsive images.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>webperf</category>
    </item>
    <item>
      <title>Stop Using react-error-boundary in Next.js? Meet next/error</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Fri, 03 Jul 2026 06:30:57 +0000</pubDate>
      <link>https://dev.to/harshmangalam/stop-using-react-error-boundary-in-nextjs-meet-nexterror-o53</link>
      <guid>https://dev.to/harshmangalam/stop-using-react-error-boundary-in-nextjs-meet-nexterror-o53</guid>
      <description>&lt;p&gt;For a long time, whenever I needed an Error Boundary in React, I reached for &lt;code&gt;react-error-boundary&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It has been the go-to solution because React itself only provides the low-level Error Boundary API.&lt;/p&gt;

&lt;p&gt;But if you're using &lt;strong&gt;Next.js App Router&lt;/strong&gt;, there's now a much cleaner option.&lt;/p&gt;

&lt;p&gt;Starting with &lt;strong&gt;Next.js 16&lt;/strong&gt;, you can use the built-in &lt;code&gt;next/error&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;Let's see why it matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Old Way
&lt;/h2&gt;

&lt;p&gt;Most React applications use &lt;code&gt;react-error-boundary&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-error-boundary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ErrorFallback&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resetErrorBoundary&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Something went wrong.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;resetErrorBoundary&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Try Again
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="na"&gt;FallbackComponent&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ErrorFallback&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;It works well, but it means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installing another dependency&lt;/li&gt;
&lt;li&gt;Learning another API&lt;/li&gt;
&lt;li&gt;Slightly different patterns from what Next.js already provides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're already using Next.js, that's no longer necessary in many cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enter &lt;code&gt;next/error&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Next.js now ships with a helper called &lt;code&gt;catchError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead of wrapping your component with &lt;code&gt;&amp;lt;ErrorBoundary /&amp;gt;&lt;/code&gt;, you simply wrap your fallback component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ErrorInfo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ErrorFallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;retry&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ErrorInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Something went wrong.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Try Again
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ErrorFallback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;No extra package.&lt;/p&gt;

&lt;p&gt;No separate Error Boundary component.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real Example
&lt;/h2&gt;

&lt;p&gt;Here's an example with a nicer UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AlertTriangle&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lucide-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ErrorInfo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/ui/button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ErrorFallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;retry&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ErrorInfo&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center gap-2 px-4 py-4 text-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AlertTriangle&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-danger h-4 w-4"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-gray text-xs"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;
          &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sm"&lt;/span&gt;
          &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"secondary"&lt;/span&gt;
          &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Try again
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center gap-3 px-5 py-10 text-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AlertTriangle&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-danger h-6 w-6"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-sm font-medium"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;
        &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sm"&lt;/span&gt;
        &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"secondary"&lt;/span&gt;
        &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Try again
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ErrorFallback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that your fallback component receives &lt;strong&gt;two things&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;props&lt;/strong&gt; → Any custom props you pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ErrorInfo&lt;/strong&gt; → Helpful methods like &lt;code&gt;retry()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Calling &lt;code&gt;retry()&lt;/code&gt; tells Next.js to attempt rendering the component again.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Feels Better
&lt;/h2&gt;

&lt;p&gt;The API is surprisingly simple.&lt;/p&gt;

&lt;p&gt;Instead of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt; &lt;span class="na"&gt;FallbackComponent&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ErrorFallback&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ErrorBoundary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You create an error boundary by exporting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;catchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ErrorFallback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your fallback stays focused on displaying the UI.&lt;/p&gt;

&lt;p&gt;Next.js handles the rest.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Should You Use It?
&lt;/h2&gt;

&lt;p&gt;If you're building a &lt;strong&gt;Next.js App Router&lt;/strong&gt; application and only need client-side Error Boundaries, &lt;code&gt;next/error&lt;/code&gt; is a great default.&lt;/p&gt;

&lt;p&gt;It gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ No additional dependency&lt;/li&gt;
&lt;li&gt;✅ Smaller bundle&lt;/li&gt;
&lt;li&gt;✅ Built into Next.js&lt;/li&gt;
&lt;li&gt;✅ Retry support out of the box&lt;/li&gt;
&lt;li&gt;✅ API that feels consistent with the framework&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Should You Remove &lt;code&gt;react-error-boundary&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;If you're starting a new Next.js project, I'd probably reach for &lt;code&gt;next/error&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;If you already have &lt;code&gt;react-error-boundary&lt;/code&gt; everywhere, there's no urgent reason to rewrite everything overnight.&lt;/p&gt;

&lt;p&gt;But for new components, using the built-in solution keeps your dependency list a little smaller and your code a little more aligned with Next.js.&lt;/p&gt;




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

&lt;p&gt;One thing I like about recent Next.js releases is that they're gradually replacing common third-party utilities with built-in APIs.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;next/error&lt;/code&gt; is another example of that.&lt;/p&gt;

&lt;p&gt;It's a small addition, but it removes a dependency, simplifies your code, and gives you an Error Boundary API that feels like it belongs in the framework.&lt;/p&gt;

&lt;p&gt;If you're using the App Router, it's definitely worth trying.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js &lt;code&gt;catchError&lt;/code&gt; documentation: &lt;a href="https://nextjs.org/docs/app/api-reference/functions/catchError" rel="noopener noreferrer"&gt;https://nextjs.org/docs/app/api-reference/functions/catchError&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Next.js 16 release notes: &lt;a href="https://nextjs.org/blog" rel="noopener noreferrer"&gt;https://nextjs.org/blog&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>TypeScript is quietly killing baseUrl (and most people haven’t noticed yet)</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Wed, 08 Apr 2026 05:13:34 +0000</pubDate>
      <link>https://dev.to/harshmangalam/typescript-is-quietly-killing-baseurl-and-most-people-havent-noticed-yet-1mbf</link>
      <guid>https://dev.to/harshmangalam/typescript-is-quietly-killing-baseurl-and-most-people-havent-noticed-yet-1mbf</guid>
      <description>&lt;p&gt;If you’re seeing this warning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yeah… it’s real.&lt;/p&gt;

&lt;p&gt;For years, we’ve been doing this 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@workspace/typescript-config/bun.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"@/*"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/*"&lt;/span&gt;&lt;span class="p"&gt;]&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;span class="p"&gt;}&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;But TypeScript is moving away from module resolution hacks.&lt;/p&gt;

&lt;p&gt;💡 The shift&lt;br&gt;
TypeScript no longer wants to resolve your imports.&lt;/p&gt;

&lt;p&gt;👉 Your runtime / bundler should do that (Bun, Vite, Next, etc.)&lt;br&gt;
👉 TypeScript should just type-check&lt;/p&gt;

&lt;p&gt;✅ The simple fix&lt;br&gt;
Just remove baseUrl.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@workspace/typescript-config/bun.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"@/*"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./src/*"&lt;/span&gt;&lt;span class="p"&gt;]&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;span class="p"&gt;}&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;⚡ Why this matters&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Future-proof (TS 7 won’t break you)&lt;/li&gt;
&lt;li&gt;Cleaner separation of concerns&lt;/li&gt;
&lt;li&gt;Matches modern tooling direction&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>🧩 Why Dialog Doesn’t Work When Wrapped with Tooltip in Radix / ShadCN UI (And How to Fix It)</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Thu, 07 Aug 2025 17:37:45 +0000</pubDate>
      <link>https://dev.to/harshmangalam/why-dialog-doesnt-work-when-wrapped-with-tooltip-in-radix-shadcn-ui-and-how-to-fix-it-4905</link>
      <guid>https://dev.to/harshmangalam/why-dialog-doesnt-work-when-wrapped-with-tooltip-in-radix-shadcn-ui-and-how-to-fix-it-4905</guid>
      <description>&lt;p&gt;When working with &lt;strong&gt;Radix UI&lt;/strong&gt; (used under the hood in &lt;a href="https://ui.shadcn.com" rel="noopener noreferrer"&gt;shadcn/ui&lt;/a&gt;), things are usually smooth — composable, accessible, and beautifully engineered.&lt;/p&gt;

&lt;p&gt;But one day, I wrapped a &lt;code&gt;DialogTrigger&lt;/code&gt; with a &lt;code&gt;Tooltip&lt;/code&gt; and…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nothing happened.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No errors. No warnings. Just a button that didn’t open the dialog. 🤯&lt;/p&gt;

&lt;p&gt;Turns out, there's a &lt;strong&gt;common but sneaky mistake&lt;/strong&gt; that trips up many devs — and it’s all about the &lt;strong&gt;order in which you nest your components&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❌ The Broken Version
&lt;/h2&gt;

&lt;p&gt;This is what I initially wrote — trying to wrap my dialog trigger in a tooltip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dialog&lt;/span&gt; &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onOpenChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DialogTrigger&lt;/span&gt; &lt;span class="na"&gt;asChild&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Tooltip&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TooltipTrigger&lt;/span&gt; &lt;span class="na"&gt;asChild&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"outline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EditIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TooltipTrigger&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TooltipContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Edit podcast&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TooltipContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Tooltip&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DialogTrigger&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DialogContent&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"max-w-4xl max-h-[80vh] overflow-y-auto"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Form goes here */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DialogContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Dialog&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this looks totally fine.&lt;/p&gt;

&lt;p&gt;But the dialog wouldn’t open when clicking the button.&lt;br&gt;
The tooltip shows, but the dialog never appears.&lt;/p&gt;

&lt;p&gt;🤔 What’s Going Wrong?&lt;br&gt;
Let’s break this down.&lt;/p&gt;

&lt;p&gt;Both DialogTrigger and TooltipTrigger from Radix use the asChild prop, which means:&lt;/p&gt;

&lt;p&gt;They don’t render any DOM element themselves.&lt;/p&gt;

&lt;p&gt;Instead, they pass event handlers like onClick to their child — which must be a real DOM element, like a .&lt;/p&gt;

&lt;p&gt;In the broken example, DialogTrigger wraps Tooltip, which is not a DOM element — it's just a React component.&lt;br&gt;
So the click event never reaches a usable target for Dialog.&lt;/p&gt;

&lt;p&gt;✅ The Working Version&lt;br&gt;
Here’s the corrected nesting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dialog&lt;/span&gt; &lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onOpenChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Tooltip&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TooltipTrigger&lt;/span&gt; &lt;span class="na"&gt;asChild&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DialogTrigger&lt;/span&gt; &lt;span class="na"&gt;asChild&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"outline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EditIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DialogTrigger&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TooltipTrigger&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TooltipContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Edit podcast&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TooltipContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Tooltip&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DialogContent&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"max-w-4xl max-h-[80vh] overflow-y-auto"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Form goes here */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;DialogContent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Dialog&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why does this work?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TooltipTrigger passes props down to DialogTrigger&lt;/li&gt;
&lt;li&gt;DialogTrigger passes props down to the final Button&lt;/li&gt;
&lt;li&gt;The Button becomes the single, shared DOM element that receives both behaviors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧠 Rule of Thumb&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Always place the outermost wrapper (like Tooltip) outside, and the final DOM element (like Button) inside both DialogTrigger and TooltipTrigger, using asChild.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>radix</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Understanding Legacy Promise Throwing Behavior in React</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Mon, 06 Jan 2025 06:39:14 +0000</pubDate>
      <link>https://dev.to/harshmangalam/understanding-legacy-promise-throwing-behavior-in-react-3kgf</link>
      <guid>https://dev.to/harshmangalam/understanding-legacy-promise-throwing-behavior-in-react-3kgf</guid>
      <description>&lt;p&gt;React is a powerful and versatile JavaScript library used for building user interfaces. One of its modern features, Suspense, allows components to handle asynchronous data gracefully. However, the concept of "Legacy Promise Throwing Behavior" in React often causes confusion among developers. This blog post aims to break down what this behavior entails, how it fits into React’s rendering process, and why it’s important to understand when working with concurrent features.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Legacy Promise Throwing Behavior?
&lt;/h2&gt;

&lt;p&gt;Legacy Promise Throwing Behavior refers to the mechanism where React components "throw" a promise during rendering. This tells React that the component is waiting for some asynchronous data to be resolved before it can be fully rendered.&lt;/p&gt;

&lt;p&gt;When a promise is thrown, React pauses rendering of that part of the component tree and instead renders a fallback UI, if defined, using Suspense. Once the promise resolves, React re-renders the component with the resolved data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features of Legacy Promise Throwing:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Throwing Promises During Rendering: Components can indicate they’re awaiting data by throwing a promise.&lt;/li&gt;
&lt;li&gt;Integration with Suspense: This behavior works seamlessly with Suspense to show fallback content.&lt;/li&gt;
&lt;li&gt;Asynchronous Data Handling: It provides a declarative way to handle async data fetching within React’s rendering lifecycle.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How Does It Work?
&lt;/h2&gt;

&lt;p&gt;Let’s take a step-by-step look at how this behavior functions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Component Throws a Promise: During rendering, a component encounters a promise and throws it.&lt;/li&gt;
&lt;li&gt;Rendering Paused: React halts rendering for that branch of the component tree.&lt;/li&gt;
&lt;li&gt;Fallback UI: If a Suspense boundary is present, React renders the fallback UI.&lt;/li&gt;
&lt;li&gt;Promise Resolves: Once the promise resolves, React resumes rendering and integrates the resolved data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Example of Legacy Promise Throwing
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Simulated fetch function&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Data loaded!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Component that throws a promise&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;AsyncComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Custom hook&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AsyncComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&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;Explanation&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetching Data: The useData hook fetches data asynchronously using the fetchData function.&lt;/li&gt;
&lt;li&gt;Throwing a Promise: If the data is not yet available, the promise is thrown.&lt;/li&gt;
&lt;li&gt;Suspense Fallback: The Suspense component displays "Loading..." until the promise resolves.&lt;/li&gt;
&lt;li&gt;Resolved Data: Once the promise resolves, the AsyncComponent renders the loaded data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Modern React and Concurrent Features
&lt;/h2&gt;

&lt;p&gt;React 18 introduced concurrent rendering, which refines how promise throwing works. Key improvements include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Time-Slicing: React’s concurrent rendering splits work into smaller chunks, keeping the UI responsive even while waiting for async data.&lt;/li&gt;
&lt;li&gt;Controlled Suspense Boundaries: Suspense boundaries handle promise throwing more gracefully.&lt;/li&gt;
&lt;li&gt;Improved Error Handling: Better error boundaries for components that fail to fetch data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;p&gt;While Legacy Promise Throwing is foundational to Suspense, developers should use modern libraries and patterns for a better experience:&lt;/p&gt;

&lt;h3&gt;
  
  
  Use React Query or SWR
&lt;/h3&gt;

&lt;p&gt;Libraries like React Query and SWR provide robust solutions for data fetching, caching, and synchronization, eliminating the need to manually throw promises.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leverage use Hook (React 18+)
&lt;/h3&gt;

&lt;p&gt;React 18 introduced the use hook (experimental) for handling promises in a cleaner, declarative way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;AsyncComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Avoid Throwing Promises Directly
&lt;/h3&gt;

&lt;p&gt;Throwing promises manually can lead to unexpected issues, especially in non-concurrent environments. Instead, rely on libraries or utilities that abstract these complexities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap Suspense for Reusability
&lt;/h3&gt;

&lt;p&gt;Encapsulate Suspense logic in reusable components for cleaner code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;WithSuspense&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Legacy Promise Throwing Behavior is a cornerstone of React’s Suspense feature, enabling seamless handling of asynchronous data during rendering. However, as React evolves, so do the tools and patterns for managing async operations. By understanding this behavior and leveraging modern practices, developers can create efficient, responsive, and maintainable applications.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Mastering Literal Types in TypeScript: true as const vs true</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Wed, 18 Dec 2024 12:03:12 +0000</pubDate>
      <link>https://dev.to/harshmangalam/mastering-literal-types-in-typescript-true-as-const-vs-true-1ego</link>
      <guid>https://dev.to/harshmangalam/mastering-literal-types-in-typescript-true-as-const-vs-true-1ego</guid>
      <description>&lt;p&gt;In TypeScript, there is a significant difference between the two statements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;clientLoader.hydrate = true as const;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;clientLoader.hydrate = true;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;FYI I have picked these example from React router v7.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Let’s break down the difference with detailed explanations and examples
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;clientLoader.hydrate = true as const;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;as const&lt;/code&gt; assertion in TypeScript is a way of telling the TypeScript compiler to treat a value as its literal type, rather than the general type. &lt;br&gt;
In this case, &lt;code&gt;true as const&lt;/code&gt; means that the type of &lt;code&gt;hydrate&lt;/code&gt; will be the literal &lt;code&gt;true&lt;/code&gt; and not &lt;code&gt;boolean&lt;/code&gt;. It essentially locks the value of hydrate to &lt;code&gt;true&lt;/code&gt; specifically.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ClientLoader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;hydrate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// The type of hydrate is set to the literal value `true`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientLoader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ClientLoader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;hydrate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;clientLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hydrate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This is valid&lt;/span&gt;

&lt;span class="c1"&gt;// clientLoader.hydrate = false; // Error: Type 'false' is not assignable to type 'true'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In the above example, &lt;code&gt;clientLoader.hydrate&lt;/code&gt; is specifically typed as &lt;code&gt;true&lt;/code&gt;. You cannot assign any value other than &lt;code&gt;true&lt;/code&gt; to &lt;code&gt;hydrate&lt;/code&gt; because of the &lt;code&gt;as const&lt;/code&gt; assertion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This type of assignment is useful when you want to enforce immutability for certain properties.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;clientLoader.hydrate = true;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without the &lt;code&gt;as const&lt;/code&gt; assertion, TypeScript will infer the type of &lt;code&gt;hydrate&lt;/code&gt; as &lt;code&gt;boolean&lt;/code&gt;. This means that &lt;code&gt;hydrate&lt;/code&gt; can be assigned any &lt;code&gt;boolean&lt;/code&gt; value &lt;code&gt;(true or false)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ClientLoader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;hydrate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// The type of hydrate is set to `boolean`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientLoader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ClientLoader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;hydrate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;clientLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hydrate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// This is valid&lt;/span&gt;
&lt;span class="nx"&gt;clientLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hydrate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// This is also valid&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In this case, since &lt;code&gt;hydrate&lt;/code&gt; is typed as &lt;code&gt;boolean&lt;/code&gt;, you can assign &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; to it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It provides flexibility to switch between both &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;&lt;code&gt;clientLoader.hydrate = true as const;&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;clientLoader.hydrate = true;&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Type of hydrate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;true&lt;/code&gt; (literal type)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;boolean&lt;/code&gt; (general type)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can only be &lt;code&gt;true&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Can be &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use Case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;When you want the property to be strictly &lt;code&gt;true&lt;/code&gt; and not allow changes&lt;/td&gt;
&lt;td&gt;When the property can hold any boolean value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Type Inference&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The type of &lt;code&gt;hydrate&lt;/code&gt; is narrowed to &lt;code&gt;true&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;The type of &lt;code&gt;hydrate&lt;/code&gt; is inferred as &lt;code&gt;boolean&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why Use as const?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Enforcing Immutability: &lt;code&gt;as const&lt;/code&gt; locks down the value so that it can’t be changed to something else. This is particularly useful when you want to ensure that a specific value is always the same throughout the program.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Literal Types for Discriminated Unions: When working with discriminated unions, &lt;code&gt;as const&lt;/code&gt; allows you to create specific cases based on literal types, as shown below:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 'pending' is a valid value&lt;/span&gt;

&lt;span class="c1"&gt;// status = 'in-progress'; // Error: Type '"in-progress"' is not assignable to type 'Status'&lt;/span&gt;

&lt;span class="c1"&gt;// With 'as const'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;taskStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Now taskStatus is narrowed down to the literal type 'pending'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;as const&lt;/code&gt; when you want to assign a specific literal value to a property and enforce that the value remains fixed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use regular assignment &lt;code&gt;(true, false, etc.)&lt;/code&gt; when you want to allow a property to accept different &lt;code&gt;boolean&lt;/code&gt; values or when the exact value doesn’t need to be restricted.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This makes as const a useful tool for more precise typing and enforcing stricter value constraints in your TypeScript code.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Celebrating 100th Open Source Contributions: A Journey of Growth and Collaboration.</title>
      <dc:creator>Harsh Mangalam</dc:creator>
      <pubDate>Tue, 27 Aug 2024 18:25:24 +0000</pubDate>
      <link>https://dev.to/harshmangalam/celebrating-100th-open-source-contributions-a-journey-of-growth-and-collaboration-4n5b</link>
      <guid>https://dev.to/harshmangalam/celebrating-100th-open-source-contributions-a-journey-of-growth-and-collaboration-4n5b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I'm thrilled to announce that I've reached a personal milestone: completing my 100th open-source contribution! This journey has been nothing short of incredible, and I'm honored to have contributed to a vibrant and diverse range of projects that have not only sharpened my skills but also allowed me to give back to the community that has given me so much.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My &lt;strong&gt;100th contribution&lt;/strong&gt; was made to the &lt;em&gt;modular-forms&lt;/em&gt; library, an open source form library with performance, type safety and bundle size in mind.&lt;/p&gt;

&lt;p&gt;If you're passionate about building cool stuff, check out my GitHub profile: &lt;a href="https://github.com/harshmangalam" rel="noopener noreferrer"&gt;https://github.com/harshmangalam&lt;/a&gt; – I'm always working on new and exciting projects!&lt;/p&gt;

&lt;h2&gt;
  
  
  A Look Back: My Open Source Journey
&lt;/h2&gt;

&lt;p&gt;Over the years, I have had the privilege of contributing to a wide variety of open-source projects, each one teaching me something new and providing me with invaluable experiences. Here are some of the projects that I've been a part of:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expo&lt;/strong&gt;&lt;br&gt;
Expo is a framework and platform for building cross-platform mobile applications using React Native. It simplifies the development process by providing a set of tools and libraries that handle common tasks like navigation, camera access, and push notifications. Expo's managed workflow allows developers to build, test, and deploy apps with minimal configuration and hassle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deno&lt;/strong&gt;&lt;br&gt;
Deno is a modern runtime for JavaScript and TypeScript built on V8 and Rust. It aims to improve security, simplicity, and performance by offering built-in TypeScript support, a secure sandboxed execution environment, and a single executable with no need for a package manager. Deno emphasizes a standard library and modularity, providing an alternative to Node.js with enhanced features for contemporary development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fresh.js&lt;/strong&gt;&lt;br&gt;
Fresh.js is a web framework for building high-performance applications with a focus on simplicity and speed. It is built on Deno and leverages its features to offer server-side rendering (SSR) and static site generation (SSG) out of the box. Fresh.js emphasizes minimal client-side JavaScript, optimizing performance by delivering fast initial loads and efficient updates. It uses a component-based architecture, similar to other modern frameworks, to facilitate building dynamic, reactive user interfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Qwik&lt;/strong&gt; &lt;br&gt;
Qwik is a modern front-end framework designed for building high-performance, instantly loading web applications. It was developed by the team at Builder.io to address the performance limitations of traditional frameworks when it comes to building complex web applications&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Qwik UI&lt;/strong&gt;&lt;br&gt;
Qwik UI is a component library designed to work seamlessly with the Qwik framework. It provides a set of pre-built, reusable UI components that can be used to quickly build user interfaces while taking full advantage of Qwik's unique performance characteristics. By leveraging Qwik's principles of resumability and instant loading, Qwik UI aims to deliver highly optimized and responsive user experiences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solid.js&lt;/strong&gt;&lt;br&gt;
SolidJS is a declarative, efficient, and flexible JavaScript library for building user interfaces. It emphasizes fine-grained reactivity, enabling high performance by updating only the parts of the DOM that change. Unlike other frameworks, SolidJS compiles components down to optimized, low-level JavaScript code, making it exceptionally fast. It offers a syntax similar to React, making it easy for React developers to transition. SolidJS also prioritizes simplicity and predictability, allowing developers to build complex applications with a straightforward and intuitive approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SolidStart&lt;/strong&gt;&lt;br&gt;
SolidStart is a full-stack framework built on top of SolidJS, designed for creating highly performant web applications. It provides features like server-side rendering (SSR), routing, and data fetching, making it easier to build scalable and efficient applications. SolidStart leverages SolidJS's fine-grained reactivity to deliver fast and seamless user experiences from the server to the client.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GraphQL Yoga&lt;/strong&gt;&lt;br&gt;
GraphQL Yoga is a fully-featured GraphQL server that is simple to set up and easy to use. It provides a flexible, plug-and-play architecture that supports various frameworks and environments, including Express, Fastify, and serverless functions. GraphQL Yoga includes features like subscriptions, real-time data, and file uploads out-of-the-box. It's designed to work seamlessly with TypeScript, offering type safety and developer-friendly tools. GraphQL Yoga aims to be lightweight yet powerful, making it suitable for both small projects and large-scale applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shotstack&lt;/strong&gt;&lt;br&gt;
Shotstack is a cloud-based video editing API that enables developers to programmatically create, edit, and render videos. It offers a range of features like transitions, effects, text overlays, and audio integration, making it possible to automate video production tasks. Shotstack supports a wide array of media formats and can handle both 2D and 3D rendering&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remix.run&lt;/strong&gt;:&lt;br&gt;
Remix.run is a modern web framework focused on optimizing user experience and performance by leveraging server-side rendering (SSR) and client-side navigation. It emphasizes data fetching and caching strategies that improve speed and responsiveness. Remix enables developers to build robust and scalable applications with a strong emphasis on traditional web fundamentals like progressive enhancement and full-page reloads. It integrates well with various backends and APIs, allowing for flexible and efficient data management. Remix's architecture aims to provide a seamless user experience and a streamlined development process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deno SaaSKit&lt;/strong&gt;&lt;br&gt;
Deno SaaSKit is a SaaS boilerplate built on Deno, designed to accelerate the development of software-as-a-service applications. It provides essential features like authentication, billing, and multi-tenancy out-of-the-box. Deno SaaSKit leverages Deno's modern runtime and TypeScript support to deliver a secure, scalable, and maintainable foundation for SaaS projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revoltchat&lt;/strong&gt;&lt;br&gt;
Revoltchat is an open-source alternative to Discord, designed for creating and managing online communities and chat environments. It offers features such as text and voice channels, user roles, and real-time messaging. Revoltchat emphasizes privacy and control, allowing users to host their own servers and manage data independently. The platform is built with a focus on flexibility and customizability, catering to various community needs and preferences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prisma&lt;/strong&gt;&lt;br&gt;
Prisma is a modern ORM (Object-Relational Mapping) tool for Node.js and TypeScript applications that simplifies database interactions. It provides a type-safe database client and a powerful schema management tool, allowing developers to define their data models using a declarative schema language. Prisma supports various databases, including PostgreSQL, MySQL, and SQLite, and offers features like automatic migrations and query optimization. It aims to streamline database workflows, improve developer productivity, and enhance the overall developer experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drizzle ORM&lt;/strong&gt;&lt;br&gt;
Drizzle ORM is a lightweight, type-safe ORM (Object-Relational Mapping) library for TypeScript and JavaScript. It focuses on simplicity and performance, providing a straightforward API for querying and managing database records. Drizzle ORM supports various databases, including PostgreSQL, MySQL, and SQLite. It emphasizes type safety and minimal configuration, making it easier for developers to work with databases while ensuring reliable and maintainable code.&lt;/p&gt;

&lt;p&gt;Open source is more than just code. It's about community, collaboration, and continuous learning. Every contribution I've made has been an opportunity to learn from others, share my knowledge, and solve real-world problems. Open source has given me the platform to experiment, innovate, and most importantly, connect with like-minded individuals who share the same passion for technology.&lt;/p&gt;

&lt;p&gt;Looking Forward&lt;br&gt;
As I celebrate this milestone, I am more motivated than ever to continue my journey in the open-source world. There are countless more projects to explore, more challenges to tackle, and more communities to engage with. I am excited about the future and the endless possibilities that lie ahead.&lt;/p&gt;

&lt;p&gt;To everyone who has been part of this journey—thank you! Here's to the next 100 contributions and beyond!&lt;/p&gt;

&lt;p&gt;Thanks.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>github</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
