<?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: Daniel Keya</title>
    <description>The latest articles on DEV Community by Daniel Keya (@danikeya).</description>
    <link>https://dev.to/danikeya</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%2F3719991%2F051657d4-7ead-4f38-9c6a-b813f1867284.jpeg</url>
      <title>DEV Community: Daniel Keya</title>
      <link>https://dev.to/danikeya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danikeya"/>
    <language>en</language>
    <item>
      <title>Day 5 of 30: Message Queues and Why Not Everything Needs an Instant Response</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Sat, 11 Jul 2026 18:01:53 +0000</pubDate>
      <link>https://dev.to/danikeya/day-5-of-30-message-queues-and-why-not-everything-needs-an-instant-response-16i4</link>
      <guid>https://dev.to/danikeya/day-5-of-30-message-queues-and-why-not-everything-needs-an-instant-response-16i4</guid>
      <description>&lt;p&gt;Day 1: the big picture. Day 2: databases. Day 3: caching. Day 4: load balancing, and how the load balancer itself becomes a new single point of failure. Today: &lt;strong&gt;message queues and asynchronous processing&lt;/strong&gt; — a topic that quietly reframed how I think about "handling a request."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Assumption I Didn't Know I Had
&lt;/h2&gt;

&lt;p&gt;Up until today, my mental model of a system was: request comes in, server does the work, response goes out, all in one continuous chain. Synchronous, start to finish.&lt;/p&gt;

&lt;p&gt;Today's lesson was basically: that assumption breaks down the moment any part of the work is slow, unreliable, or doesn't need to happen &lt;em&gt;right now&lt;/em&gt;. Sending a confirmation email, resizing an uploaded image, generating a report, notifying a third-party service — none of that needs to block the response the user is waiting on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Message Queue Actually Does
&lt;/h2&gt;

&lt;p&gt;A message queue sits between two parts of a system — a &lt;strong&gt;producer&lt;/strong&gt; that creates a task or event, and a &lt;strong&gt;consumer&lt;/strong&gt; that processes it — and holds messages in between until the consumer is ready. The producer doesn't wait around for the consumer to finish; it just drops the message in the queue and moves on.&lt;/p&gt;

&lt;p&gt;That single shift — not waiting — is what decoupling really means in practice. The producer and consumer don't need to run at the same speed, be available at the same time, or even know much about each other. They just agree on the shape of the message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Scaling
&lt;/h2&gt;

&lt;p&gt;A few reasons this clicked for me as a system design concept, not just an engineering convenience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Load leveling&lt;/strong&gt; — if a sudden burst of requests comes in, the queue absorbs the spike. Consumers can keep processing at a steady rate instead of getting overwhelmed all at once. This is the async equivalent of what caching does for reads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure isolation&lt;/strong&gt; — if the consumer service goes down temporarily, messages just wait in the queue instead of being lost or crashing the producer. When the consumer comes back up, it picks up where it left off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent scaling&lt;/strong&gt; — producers and consumers can scale separately. If processing is the bottleneck, you add more consumers without touching the producer at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ties directly back to horizontal scaling from Day 1 — message queues are one of the main tools that make horizontal scaling of &lt;em&gt;background work&lt;/em&gt; practical, not just scaling the request-handling servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delivery Guarantees: The Part That Gets Complicated Fast
&lt;/h2&gt;

&lt;p&gt;I expected this section to be simple. It was not. Queues generally offer one of a few delivery guarantees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;At-most-once&lt;/strong&gt; — a message is delivered zero or one times. Fast, but messages can be lost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;At-least-once&lt;/strong&gt; — a message is guaranteed to be delivered, but might be delivered more than once. Common default, but it means consumers need to be &lt;strong&gt;idempotent&lt;/strong&gt; — processing the same message twice shouldn't cause duplicate side effects (e.g., charging a customer twice).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exactly-once&lt;/strong&gt; — the message is delivered exactly one time, no duplicates, no loss. Sounds ideal, but it's genuinely hard to guarantee in a distributed system and usually comes with real performance cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idempotency point stuck with me the most. It's not enough to just add a queue — the consumer logic has to be written defensively, because "at-least-once" is the realistic default in most systems, not "exactly-once."&lt;/p&gt;

&lt;h2&gt;
  
  
  Queue vs. Pub/Sub
&lt;/h2&gt;

&lt;p&gt;I also drew a distinction I'd been fuzzy on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Message queue (point-to-point)&lt;/strong&gt; — each message is processed by exactly one consumer. Good for distributing discrete units of work, like "process this uploaded file."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pub/Sub (publish-subscribe)&lt;/strong&gt; — a message is broadcast to &lt;em&gt;all&lt;/em&gt; subscribers interested in that event. Good for things like "notify every service that cares that an order was placed" — inventory, billing, and notifications can all react independently to the same event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same underlying idea (decoupled, asynchronous communication), but the delivery pattern is fundamentally different depending on whether you need one consumer or many.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Clicked Today
&lt;/h2&gt;

&lt;p&gt;The biggest mental shift: not every part of a system needs to run inside the request-response cycle. Deciding what's synchronous and what's asynchronous is itself a design decision — and getting it right is often what separates a system that stays responsive under load from one that falls over the moment traffic spikes.&lt;/p&gt;

&lt;p&gt;It also reinforced something from Day 3 and Day 4: decoupling components (via caching, load balancers, or queues) keeps showing up as the general strategy for making a system resilient. Different tools, same underlying move.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tomorrow
&lt;/h2&gt;

&lt;p&gt;Next up: &lt;strong&gt;API design and communication patterns&lt;/strong&gt; — REST vs. GraphQL vs. gRPC, and how services actually talk to each other once you've got more than one of them.&lt;/p&gt;

&lt;p&gt;If you've built something with a message queue, I'd love to hear how you handled idempotency — that feels like the kind of thing that's easy to get wrong quietly.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is part of a 30-day series on learning system design from scratch. Catch up on &lt;a href="https://dev.to/danikeya"&gt;Day 1&lt;/a&gt;, &lt;a href="https://dev.to/danikeya"&gt;Day 2&lt;/a&gt;, &lt;a href="https://dev.to/danikeya"&gt;Day 3&lt;/a&gt;, and &lt;a href="https://dev.to/danikeya"&gt;Day 4&lt;/a&gt; if you missed them.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>beginners</category>
      <category>learning</category>
      <category>messagequeues</category>
    </item>
    <item>
      <title>title: Day 4 of 30: Load Balancing and the Single Point of Failure Problem</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Wed, 08 Jul 2026 20:21:42 +0000</pubDate>
      <link>https://dev.to/danikeya/title-day-4-of-30-load-balancing-and-the-single-point-of-failure-problem-2o7b</link>
      <guid>https://dev.to/danikeya/title-day-4-of-30-load-balancing-and-the-single-point-of-failure-problem-2o7b</guid>
      <description>&lt;p&gt;Day 1: the big picture. Day 2: databases. Day 3: caching, and how it's really a consistency problem in disguise. Today: &lt;strong&gt;load balancing&lt;/strong&gt; — how traffic actually gets spread across servers, and the ways that can quietly go wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Load Balancers Exist
&lt;/h2&gt;

&lt;p&gt;Once you've horizontally scaled (Day 1 flashback) and have multiple servers instead of one, something needs to decide which server handles which request. That's the load balancer's job: sit between the client and your fleet of servers, and distribute incoming traffic so no single server gets overwhelmed while others sit idle.&lt;/p&gt;

&lt;p&gt;It sounds simple — "just spread the requests out" — but &lt;em&gt;how&lt;/em&gt; you spread them out turns out to matter a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancing Algorithms
&lt;/h2&gt;

&lt;p&gt;I went through the main ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Round robin&lt;/strong&gt; — requests go to servers in sequence, one after another. Simple, but doesn't account for server load — if one request is expensive and another is cheap, round robin doesn't know or care.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least connections&lt;/strong&gt; — send the next request to whichever server currently has the fewest active connections. More adaptive than round robin, especially when requests vary a lot in how long they take.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weighted round robin / weighted least connections&lt;/strong&gt; — same ideas as above, but servers with more capacity get proportionally more traffic. Useful when your fleet isn't made of identical machines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP hash&lt;/strong&gt; — the client's IP determines which server it's routed to, so the same client tends to land on the same server. This matters for &lt;strong&gt;session persistence&lt;/strong&gt; (also called "sticky sessions") — some applications need a user's requests to keep hitting the same server, e.g., if session data is stored locally on that server instead of in a shared store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The thing that stood out: there's no universally "best" algorithm. Round robin is fine when requests are roughly uniform. Least connections is better when they're not. IP hash matters when statefulness matters. It's another trade-off decision, not a default setting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 4 vs. Layer 7 Load Balancing
&lt;/h2&gt;

&lt;p&gt;This distinction took me a minute to really get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Layer 4 (transport layer)&lt;/strong&gt; load balancers route based on IP address and port, without looking at the actual content of the request. Faster, simpler, but less flexible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer 7 (application layer)&lt;/strong&gt; load balancers can inspect the actual request — HTTP headers, URL paths, cookies — and make smarter routing decisions, like sending &lt;code&gt;/api/video&lt;/code&gt; traffic to one set of servers and &lt;code&gt;/api/search&lt;/code&gt; to another. More flexible, but more overhead per request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This maps neatly onto the classic latency vs. flexibility trade-off from Day 1: Layer 4 is faster because it knows less; Layer 7 is smarter because it does more work per request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Health Checks: How the Load Balancer Knows What's Alive
&lt;/h2&gt;

&lt;p&gt;A load balancer is useless if it keeps sending traffic to a server that's already down. Health checks solve this — the load balancer periodically pings each server (or checks a dedicated health endpoint), and stops routing traffic to any server that fails to respond. This was a good reminder that load balancing isn't just about distribution, it's also about &lt;strong&gt;failure detection&lt;/strong&gt; — the load balancer is quietly doing double duty as a monitoring system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Load Balancer Becomes a Single Point of Failure
&lt;/h2&gt;

&lt;p&gt;Here's the part that really made me stop and think: I spent three days learning how to avoid single points of failure by scaling horizontally — only to introduce one giant new single point of failure sitting in front of all those servers. If the load balancer itself goes down, it doesn't matter how many healthy backend servers you have.&lt;/p&gt;

&lt;p&gt;The common fix is to &lt;strong&gt;not have just one load balancer&lt;/strong&gt; — instead, you run multiple load balancer instances behind something like DNS round robin or a floating/virtual IP, so there's no single machine the entire system depends on. It's a very "turtles all the way down" realization: every layer you add to solve a scaling problem can itself become the next bottleneck or failure point if you don't also scale and replicate that layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Clicked Today
&lt;/h2&gt;

&lt;p&gt;Load balancing isn't just "spread traffic evenly." It's a small system of its own, with its own trade-offs (routing algorithm, OSI layer, statefulness) and its own failure modes (the load balancer itself needs redundancy). I'm noticing a theme across all four days now: &lt;strong&gt;every solution to a scaling problem introduces a new, smaller version of the same problem one layer up.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tomorrow
&lt;/h2&gt;

&lt;p&gt;Next up: &lt;strong&gt;message queues and asynchronous processing&lt;/strong&gt; — why not everything needs to happen in the request-response cycle, and how queues help decouple services from each other.&lt;/p&gt;

&lt;p&gt;If you've dealt with a load balancer misconfiguration that caused uneven traffic or a nasty outage, I'd love to hear about it — feels like exactly the kind of thing that's obvious in hindsight and invisible beforehand.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is part of a 30-day series on learning system design from scratch. Catch up on &lt;a href="https://dev.to/danikeya"&gt;Day 1&lt;/a&gt;, &lt;a href="https://dev.to/danikeya"&gt;Day 2&lt;/a&gt;, and &lt;a href="https://dev.to/danikeya"&gt;Day 3&lt;/a&gt; if you missed them.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>beginners</category>
      <category>learning</category>
      <category>loadbalancing</category>
    </item>
    <item>
      <title>Day 3 of 30: Caching, and Why Invalidation Really Is That Hard</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Tue, 07 Jul 2026 20:52:07 +0000</pubDate>
      <link>https://dev.to/danikeya/day-3-of-30-caching-and-why-invalidation-really-is-that-hard-175i</link>
      <guid>https://dev.to/danikeya/day-3-of-30-caching-and-why-invalidation-really-is-that-hard-175i</guid>
      <description>&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Day 1 was the big picture (client-server, scaling, latency vs. throughput). Day 2 went into databases (SQL vs. NoSQL, replication, sharding). Today's topic was one I thought I already understood: &lt;strong&gt;caching&lt;/strong&gt;. Turns out I only understood the easy 20% of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Caching Exists
&lt;/h2&gt;

&lt;p&gt;The core idea is simple: fetching data is expensive (database queries, network calls, computation), so you store a copy of the result somewhere faster and cheaper to access, and serve from that copy instead of redoing the work every time.&lt;/p&gt;

&lt;p&gt;But "store a copy somewhere faster" hides a lot of decisions: &lt;em&gt;where&lt;/em&gt; do you store it, &lt;em&gt;how long&lt;/em&gt; do you keep it, and &lt;em&gt;how do you know&lt;/em&gt; when that copy is no longer accurate?&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Caches Live
&lt;/h2&gt;

&lt;p&gt;I mapped out the different layers where caching shows up in a typical system, and it's more places than I expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client-side caching&lt;/strong&gt; — browser cache, mobile app cache. Avoids hitting the network at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CDN caching&lt;/strong&gt; — caching static assets (images, scripts, videos) geographically close to the user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application-layer caching&lt;/strong&gt; — an in-memory store like Redis or Memcached sitting between your app server and your database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database caching&lt;/strong&gt; — query result caching or buffer pools built into the database itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern I noticed: the closer the cache is to the user, the faster it is, but the more stale it's likely to become and the harder it is to invalidate reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching Strategies
&lt;/h2&gt;

&lt;p&gt;A few patterns kept coming up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache-aside (lazy loading)&lt;/strong&gt; — the application checks the cache first; on a miss, it fetches from the database and writes the result to the cache. Simple, and only caches what's actually requested, but the first request always pays the full cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write-through&lt;/strong&gt; — data is written to the cache and the database at the same time. Keeps the cache consistent, but adds latency to every write.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write-behind (write-back)&lt;/strong&gt; — data is written to the cache immediately and to the database asynchronously later. Fast writes, but riskier if the cache fails before the write reaches the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these is universally "correct." Cache-aside is the one I'd reach for by default, but write-through makes sense when staleness is unacceptable, and write-behind makes sense when write throughput matters more than durability guarantees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Invalidation: The Actually Hard Part
&lt;/h2&gt;

&lt;p&gt;This is where the famous line clicked for me: there really are only two hard problems in computer science — cache invalidation, naming things, and off-by-one errors (the joke itself is a joke about how hard naming and counting things are). Invalidation is hard because you're trying to answer "has the source of truth changed?" without constantly re-checking the source of truth, which would defeat the point of caching in the first place.&lt;/p&gt;

&lt;p&gt;The strategies I looked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TTL (time-to-live)&lt;/strong&gt; — the cache entry just expires after a fixed time. Simple, predictable, but you're always trading off freshness against cache-hit rate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit invalidation&lt;/strong&gt; — when the underlying data changes, the application actively tells the cache to drop or update that entry. More accurate, but adds coupling between every write path and the cache layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-based invalidation&lt;/strong&gt; — changes publish an event (e.g., through a message queue), and any cache watching that event invalidates itself. More scalable across multiple services, but adds infrastructure and a new failure mode: what if the event never arrives?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cache Stampede — A Failure Mode I Hadn't Considered
&lt;/h2&gt;

&lt;p&gt;One thing that stood out: what happens when a popular cache entry expires and a huge number of requests hit the database at the exact same moment because they all missed the cache simultaneously? This is called a &lt;strong&gt;cache stampede&lt;/strong&gt; (or thundering herd), and it's a good example of how a cache — a tool meant to protect your database — can end up hammering it hardest at the worst possible moment if you're not careful. Mitigations like staggered expiration times or "locking" so only one request repopulates the cache while others wait came up as common fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Clicked Today
&lt;/h2&gt;

&lt;p&gt;Caching looks like a performance optimization on the surface, but it's really a consistency problem wearing a performance-optimization costume. Every caching decision is really a decision about how stale you're willing to let your data be, and for how long, in exchange for speed.&lt;/p&gt;

&lt;p&gt;That's the same trade-off shape I kept running into on Day 1 (CAP theorem) and Day 2 (replication). It's starting to feel like most of system design is a small number of trade-offs showing up over and over in different clothes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tomorrow
&lt;/h2&gt;

&lt;p&gt;Next up: &lt;strong&gt;load balancing&lt;/strong&gt; — how traffic actually gets distributed across servers, different load balancing algorithms, and where load balancers themselves become a single point of failure if you're not careful.&lt;/p&gt;

&lt;p&gt;If you've been burned by a cache invalidation bug in production, I'd genuinely love to hear the story — those tend to be the most memorable ones.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is part of a 30-day series on learning system design from scratch. Catch up on &lt;a href="https://dev.to/danikeya"&gt;Day 1&lt;/a&gt; and &lt;a href="https://dev.to/danikeya"&gt;Day 2&lt;/a&gt; if you missed them.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>beginners</category>
      <category>learning</category>
      <category>caching</category>
    </item>
    <item>
      <title>Day 2 of 30: Databases, Replication, and Sharding published: false tags: systemdesign, beginners, learning, databases</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Mon, 06 Jul 2026 16:25:47 +0000</pubDate>
      <link>https://dev.to/danikeya/day-2-of-30-databases-replication-and-sharding-published-false-tags-systemdesign-beginners-48do</link>
      <guid>https://dev.to/danikeya/day-2-of-30-databases-replication-and-sharding-published-false-tags-systemdesign-beginners-48do</guid>
      <description>&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Yesterday was about the big picture — client-server architecture, scaling, latency vs. throughput, and a first look at the CAP theorem. Today I went one layer deeper: &lt;strong&gt;databases&lt;/strong&gt;, and specifically, how they hold up when a system needs to scale.&lt;/p&gt;

&lt;p&gt;This turned out to be a bigger topic than I expected. I thought "SQL vs. NoSQL" would be the whole day. It was maybe a third of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  SQL vs. NoSQL: Less "Which Is Better," More "Which Fits"
&lt;/h2&gt;

&lt;p&gt;I used to think of this as a binary choice where one option was obviously modern and the other outdated. That's the wrong frame. It's really about what shape your data takes and how you need to query it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQL (relational) databases&lt;/strong&gt; — think PostgreSQL, MySQL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structured data with defined relationships&lt;/li&gt;
&lt;li&gt;Strong consistency guarantees (ACID transactions)&lt;/li&gt;
&lt;li&gt;Great when your data has clear relationships and you need to enforce integrity (e.g., financial systems, orders tied to users tied to inventory)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NoSQL databases&lt;/strong&gt; — think MongoDB, Cassandra, DynamoDB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flexible or schema-less data models&lt;/li&gt;
&lt;li&gt;Built to scale horizontally more naturally&lt;/li&gt;
&lt;li&gt;Great for unstructured or fast-changing data, high write throughput, or massive scale where strict consistency can be relaxed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real takeaway: the choice isn't about which database is "better" — it's about which trade-offs your system can tolerate. A banking system probably shouldn't sacrifice consistency for speed. A social media feed's like counter probably can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replication: Copies for Reliability and Speed
&lt;/h2&gt;

&lt;p&gt;Replication means keeping copies of the same data on multiple machines. I looked at two common patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Leader-follower (master-replica) replication&lt;/strong&gt; — one node handles writes, and changes propagate to follower nodes that mostly handle reads. This spreads read load and adds redundancy if the leader goes down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-leader replication&lt;/strong&gt; — multiple nodes can accept writes, which is more resilient but opens the door to write conflicts that need to be resolved somehow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The concept that stuck with me most: replication isn't free. The moment you have copies of data, you have to decide how quickly those copies need to agree with each other. That's where I ran straight back into the CAP theorem from yesterday — replication is where "choose consistency or availability" actually shows up in a real design decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharding: Splitting Data Across Machines
&lt;/h2&gt;

&lt;p&gt;If replication is about copying the &lt;em&gt;same&lt;/em&gt; data across machines, &lt;strong&gt;sharding&lt;/strong&gt; is about splitting &lt;em&gt;different&lt;/em&gt; data across machines. Instead of one giant database holding everything, you partition data — often by a key like user ID or region — so no single machine has to hold or serve all of it.&lt;/p&gt;

&lt;p&gt;A few things I noted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sharding key choice matters a lot.&lt;/strong&gt; Pick a bad key (like something unevenly distributed) and you end up with "hot shards" — some machines overloaded while others sit idle.&lt;/li&gt;
&lt;li&gt;Sharding solves a storage/throughput problem, but introduces new ones: queries that need data from multiple shards get more complex, and cross-shard transactions are painful.&lt;/li&gt;
&lt;li&gt;This is usually a "last resort" scaling technique — you shard once vertical scaling and replication aren't enough anymore.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Replication + Sharding Together
&lt;/h2&gt;

&lt;p&gt;In real large-scale systems, these aren't either/or — they're often combined. You shard data across multiple database clusters, and &lt;em&gt;within&lt;/em&gt; each shard, you replicate for redundancy and read scaling. It was helpful to picture this as a grid: shards along one axis, replicas along the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Clicked Today
&lt;/h2&gt;

&lt;p&gt;The biggest realization: most of these decisions come back to the same question I hit yesterday — &lt;strong&gt;what are you willing to give up, and when?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give up some consistency to get more availability&lt;/li&gt;
&lt;li&gt;Give up simplicity to get more scale&lt;/li&gt;
&lt;li&gt;Give up flexibility to get stronger guarantees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Database design isn't a checklist. It's a series of trade-off calls based on what the system actually needs to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tomorrow
&lt;/h2&gt;

&lt;p&gt;Next up: &lt;strong&gt;caching&lt;/strong&gt;. Where caches fit in a system, cache invalidation strategies, and why "there are only two hard things in computer science: cache invalidation and naming things" is apparently a very real problem and not just a joke.&lt;/p&gt;

&lt;p&gt;If you work with distributed databases day to day — what's a sharding or replication decision that bit you later on? I'd love to hear the war stories.&lt;/p&gt;




&lt;p&gt;*This is part of a 30-day series on learning system design from scratch. Catch up on &lt;a href="https://dev.to/danikeya"&gt;Day 1&lt;/a&gt; if you missed it.*v&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>learning</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Day 1 of 30: Kicking Off My System Design Learning Journey published: false tags: systemdesign, beginners, learning, softwareengineering</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Sun, 05 Jul 2026 13:37:40 +0000</pubDate>
      <link>https://dev.to/danikeya/day-1-of-30-kicking-off-my-system-design-learning-journey-published-false-tags-systemdesign-2o8k</link>
      <guid>https://dev.to/danikeya/day-1-of-30-kicking-off-my-system-design-learning-journey-published-false-tags-systemdesign-2o8k</guid>
      <description>&lt;h2&gt;
  
  
  Why I'm Doing This
&lt;/h2&gt;

&lt;p&gt;I've been writing code professionally for a while now, but there's a gap in my knowledge that keeps showing up in interviews and in my own projects: &lt;strong&gt;system design&lt;/strong&gt;. I can build a feature, ship an API, write clean code — but ask me to design something that needs to handle millions of users, and I start hand-waving.&lt;/p&gt;

&lt;p&gt;So I'm giving myself 30 days to fix that. This is Day 1 of a series where I'll document what I learn, the mistakes I make, and the "aha" moments along the way. If you're on a similar journey, follow along — maybe we can learn together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Even Is System Design?
&lt;/h2&gt;

&lt;p&gt;At its core, system design is about answering one question: &lt;strong&gt;how do you build software that works reliably at scale?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That means thinking about things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How does data move between a client and a server?&lt;/li&gt;
&lt;li&gt;What happens when one server isn't enough?&lt;/li&gt;
&lt;li&gt;How do you keep data consistent across multiple machines?&lt;/li&gt;
&lt;li&gt;What breaks first when traffic spikes 100x?&lt;/li&gt;
&lt;li&gt;How do you design for failure, not just for the happy path?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's less about writing code and more about making trade-offs. Every decision in system design — cache vs. no cache, SQL vs. NoSQL, sync vs. async — comes with a cost. Today was about internalizing that mindset shift.&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics I Covered Today
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Client-Server Architecture
&lt;/h3&gt;

&lt;p&gt;The absolute foundation. A client sends a request, a server processes it and sends back a response. Simple in theory, but I spent time really understanding the layers involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS resolution&lt;/li&gt;
&lt;li&gt;Load balancers&lt;/li&gt;
&lt;li&gt;Application servers&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mapping out a basic request lifecycle (browser → DNS → load balancer → server → database → back) made a lot of "why do we need X" questions click into place.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Vertical vs. Horizontal Scaling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vertical scaling&lt;/strong&gt; = throwing more resources (CPU, RAM) at a single machine. Simple, but has a ceiling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Horizontal scaling&lt;/strong&gt; = adding more machines. More complex (hello, distributed systems problems), but it's how you actually scale to millions of users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key takeaway: almost every large-scale system eventually needs to scale horizontally, and that decision ripples into everything else — session management, data consistency, caching strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Latency vs. Throughput
&lt;/h3&gt;

&lt;p&gt;Two terms I always mixed up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Latency&lt;/strong&gt; — how long a single request takes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput&lt;/strong&gt; — how many requests you can handle per unit of time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can optimize for one at the expense of the other. Understanding which one matters more for a given system (e.g., a stock trading platform cares deeply about latency; a batch data pipeline cares more about throughput) is a design decision in itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The CAP Theorem (just the surface)
&lt;/h3&gt;

&lt;p&gt;I only scratched the surface here, but the core idea stuck: in a distributed system, you can't have perfect &lt;strong&gt;C&lt;/strong&gt;onsistency, &lt;strong&gt;A&lt;/strong&gt;vailability, and &lt;strong&gt;P&lt;/strong&gt;artition tolerance all at once. Since network partitions are a fact of life, real systems have to choose between prioritizing consistency or availability when a partition happens.&lt;/p&gt;

&lt;p&gt;I know I'll be coming back to this one in more depth later in the series.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Study Approach for These 30 Days
&lt;/h2&gt;

&lt;p&gt;To keep this from turning into passive video-watching, I'm structuring each day like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Learn one core concept&lt;/strong&gt; (30–45 minutes of reading/videos)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sketch it out&lt;/strong&gt; — diagrams, not just notes. System design is visual.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explain it simply&lt;/strong&gt; — if I can't explain a concept in plain English, I don't actually understand it yet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write it down&lt;/strong&gt; — hence this series&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;Tomorrow I'm diving into &lt;strong&gt;databases&lt;/strong&gt;: SQL vs. NoSQL, when to use each, and how replication and sharding actually work under the hood.&lt;/p&gt;

&lt;p&gt;If you've done a deep dive into system design before, I'd love to hear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What tripped you up early on?&lt;/li&gt;
&lt;li&gt;Any resources you'd recommend?&lt;/li&gt;
&lt;li&gt;Anything you wish someone had told you on day 1?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Drop a comment below. See you on Day 2. 
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This is part of a 30-day series on learning system design from scratch. Follow along for the rest of the journey.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>beginners</category>
      <category>learning</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Why I Fell in Love with Go — And Why You Should Give It a Chance</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Thu, 04 Jun 2026 14:16:50 +0000</pubDate>
      <link>https://dev.to/danikeya/why-i-fell-in-love-with-go-and-why-you-should-give-it-a-chance-3ao7</link>
      <guid>https://dev.to/danikeya/why-i-fell-in-love-with-go-and-why-you-should-give-it-a-chance-3ao7</guid>
      <description>&lt;p&gt;&lt;em&gt;Tags: go, golang, beginners, programming&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you told me two years ago that I'd be writing a love letter to a programming language, I'd have laughed. But here I am.&lt;/p&gt;

&lt;p&gt;Go (or Golang) changed the way I think about software development. And if you haven't tried it yet — or tried it and gave up — I want to make the case for why 2024 is the perfect year to give it a real shot.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Even Is Go?
&lt;/h2&gt;

&lt;p&gt;Go is an open-source programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. It was released in 2009, but it has exploded in popularity over the last few years, powering tools you probably use every day: &lt;strong&gt;Docker&lt;/strong&gt;, &lt;strong&gt;Kubernetes&lt;/strong&gt;, &lt;strong&gt;Terraform&lt;/strong&gt;, &lt;strong&gt;Prometheus&lt;/strong&gt;, and more.&lt;/p&gt;

&lt;p&gt;It sits in a sweet spot: it has the performance of a compiled language like C, but it &lt;em&gt;feels&lt;/em&gt; almost as productive as Python or JavaScript. That's a rare combination.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Things That Will Surprise You
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The Simplicity Is the Point
&lt;/h3&gt;

&lt;p&gt;Go has around 25 keywords. Compare that to Java (~50) or C++ (~90+). The language designers made a deliberate choice: &lt;strong&gt;less is more&lt;/strong&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;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="s"&gt;"fmt"&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, Gopher! 🐹"&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;That's it. No classes. No inheritance. No decorators. Just clean, readable code. When you read someone else's Go code, you can &lt;em&gt;actually understand it&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Concurrency Is a First-Class Citizen
&lt;/h3&gt;

&lt;p&gt;One of Go's killer features is &lt;strong&gt;goroutines&lt;/strong&gt; — lightweight threads that let you run things concurrently without the headaches of traditional threading.&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;"time"&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;sayHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&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;Millisecond&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, %s!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&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="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="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Charlie"&lt;/span&gt;&lt;span class="p"&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;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&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;Millisecond&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;Launching a goroutine costs just a few kilobytes of memory. You can run hundreds of thousands of them. This makes Go &lt;em&gt;exceptional&lt;/em&gt; for building APIs, microservices, and anything that handles lots of simultaneous connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Tooling Is Incredible
&lt;/h3&gt;

&lt;p&gt;Go ships with everything you need baked in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;go fmt&lt;/code&gt; — formats your code automatically (no more arguments about tabs vs spaces)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;go test&lt;/code&gt; — runs your tests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;go build&lt;/code&gt; — compiles to a single binary&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;go vet&lt;/code&gt; — catches common mistakes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;go mod&lt;/code&gt; — manages dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No decision fatigue. No webpack configs. No 47 different linting tools to choose from. You just... write code.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. It Compiles to a Single Binary
&lt;/h3&gt;

&lt;p&gt;When you build a Go application, you get &lt;strong&gt;one binary file&lt;/strong&gt;. No runtime to install. No dependencies to bundle. You can copy that file to any Linux server and it will just run.&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="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux &lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;amd64 go build &lt;span class="nt"&gt;-o&lt;/span&gt; myapp &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For DevOps and deployment, this is a game-changer.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real Example: Building a Simple HTTP Server
&lt;/h2&gt;

&lt;p&gt;Here's a fully working HTTP server in Go. No frameworks. No npm install. Just Go's standard library:&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;"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;helloHandler&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;Fprintf&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;"Welcome to Go! You're going to love it here. 🐹"&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;http&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;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;helloHandler&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;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server running on http://localhost:8080"&lt;/span&gt;&lt;span class="p"&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="no"&gt;nil&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;Run it with &lt;code&gt;go run main.go&lt;/code&gt;. That's a production-grade HTTP server in under 15 lines.&lt;/p&gt;




&lt;h2&gt;
  
  
  "But Go Doesn't Have Generics…"
&lt;/h2&gt;

&lt;p&gt;It does now! Go 1.18 (released in 2022) introduced generics, one of the most requested features in the language's history. The Go team took their time to get it right, and the result is a clean, practical implementation:&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;Map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fn&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;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;U&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="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;U&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;slice&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&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;slice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&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="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The language keeps getting better while staying true to its philosophy of simplicity.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Word of Encouragement 💪
&lt;/h2&gt;

&lt;p&gt;Learning a new programming language can feel overwhelming. You're going to write weird code at first. You're going to fight the compiler. You're going to wonder why there are no classes and feel slightly lost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's completely normal. That's part of the process.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's what I want you to know:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Go community is one of the most welcoming in tech. The error messages are actually helpful. The documentation at &lt;a href="https://pkg.go.dev" rel="noopener noreferrer"&gt;pkg.go.dev&lt;/a&gt; is outstanding. And the moment things click — the moment you write a concurrent program that handles 10,000 requests per second on a tiny server — it's &lt;em&gt;deeply satisfying&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You don't need to be a senior engineer to learn Go. You don't need a computer science degree. If you can write a &lt;code&gt;for&lt;/code&gt; loop in any language, you can start learning Go today.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Start
&lt;/h2&gt;

&lt;p&gt;Here are the best free resources to get going (pun intended):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://go.dev/tour/" rel="noopener noreferrer"&gt;A Tour of Go&lt;/a&gt;&lt;/strong&gt; — The official interactive tutorial. Do this first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://gobyexample.com/" rel="noopener noreferrer"&gt;Go by Example&lt;/a&gt;&lt;/strong&gt; — Hands-on examples for every feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://play.golang.org/" rel="noopener noreferrer"&gt;The Go Playground&lt;/a&gt;&lt;/strong&gt; — Write and run Go in your browser, no install needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://go.dev/doc/effective_go" rel="noopener noreferrer"&gt;Effective Go&lt;/a&gt;&lt;/strong&gt; — Once you know the basics, this will make you write &lt;em&gt;good&lt;/em&gt; Go.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Go won't solve every problem. It's not the best choice for machine learning, desktop apps, or scripting. But for &lt;strong&gt;backend services, CLIs, DevOps tooling, and APIs&lt;/strong&gt;, it is hard to beat.&lt;/p&gt;

&lt;p&gt;If you're a developer looking to add a powerful, pragmatic language to your toolkit — one that will make you more productive and more employable — Go deserves a serious look.&lt;/p&gt;

&lt;p&gt;Start small. Build a CLI. Write a small REST API. Deploy it as a single binary and feel the magic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Gopher community is waiting for you. 🐹&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Did this post inspire you to try Go? Drop a comment below — I'd love to hear what you're building. And if you're already a Gopher, what was the moment Go finally clicked for you?&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this helpful, consider following me for more posts on Go, backend development, and software craftsmanship.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>go</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Building My First React Component with TypeScript: A Beginner's Breakdown</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Tue, 02 Jun 2026 21:53:12 +0000</pubDate>
      <link>https://dev.to/danikeya/building-my-first-react-component-with-typescript-a-beginners-breakdown-5783</link>
      <guid>https://dev.to/danikeya/building-my-first-react-component-with-typescript-a-beginners-breakdown-5783</guid>
      <description>&lt;p&gt;So I just started learning React with TypeScript, and I want to share what I built and — more importantly — &lt;em&gt;what I actually learned&lt;/em&gt; from it. If you're also new to this stack, this one's for you.&lt;/p&gt;

&lt;p&gt;Here's the component I wrote:&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;useState&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&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;Fragment&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/jsx-runtime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;items&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;heading&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="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;ListGroup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heading&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectdIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;Fragment&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;h1&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;heading&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;h1&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;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;No item found&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="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&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;"list-group"&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;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;selectdIndex&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;
                &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list-group-item active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list-group-item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&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="p"&gt;{&lt;/span&gt;
              &lt;span class="nf"&gt;setSelectedIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&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;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&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;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;ul&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;Fragment&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's a &lt;code&gt;ListGroup&lt;/code&gt; component — a clickable list that highlights whichever item you select. Simple, but packed with fundamentals. Let me walk you through what I learned.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. TypeScript Interfaces for Props
&lt;/h2&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;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;items&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;heading&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In plain React (JavaScript), you can pass &lt;em&gt;anything&lt;/em&gt; as props and React won't complain — until something breaks at runtime. TypeScript fixes this by letting you define exactly what a component expects.&lt;/p&gt;

&lt;p&gt;Here, I'm saying: "This component must receive an array of strings (&lt;code&gt;items&lt;/code&gt;) and a string (&lt;code&gt;heading&lt;/code&gt;). Nothing else, nothing less."&lt;/p&gt;

&lt;p&gt;The component signature then uses &lt;strong&gt;destructuring&lt;/strong&gt; to pull those props out cleanly:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ListGroup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heading&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is cleaner than writing &lt;code&gt;props.items&lt;/code&gt; and &lt;code&gt;props.heading&lt;/code&gt; everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. useState — Tracking Which Item Is Selected
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectdIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSelectedIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;useState&lt;/code&gt; is React's way of giving a component memory. Without it, clicking an item would do nothing visible — React wouldn't know anything changed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-1&lt;/code&gt; is the initial value, meaning &lt;em&gt;nothing is selected yet&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;selectdIndex&lt;/code&gt; holds the current state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setSelectedIndex&lt;/code&gt; is the function we call to update it&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Quick note&lt;/strong&gt;: There's a typo here — &lt;code&gt;selectdIndex&lt;/code&gt; should be &lt;code&gt;selectedIndex&lt;/code&gt;. These things happen when you're learning! TypeScript won't catch variable name typos, only type mismatches.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. Fragment — Because JSX Needs One Root Element
&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;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;Fragment&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;h1&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;heading&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;h1&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;Fragment&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;p&gt;JSX has a rule: every component must return a &lt;strong&gt;single root element&lt;/strong&gt;. But wrapping everything in an extra &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; just to satisfy that rule can mess up your CSS layout.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Fragment&lt;/code&gt; is the solution — it's an invisible wrapper that groups elements without adding anything to the DOM. You can also write it as the shorthand &lt;code&gt;&amp;lt;&amp;gt;...&amp;lt;/&amp;gt;&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Conditional Rendering
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;No item found&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a neat React pattern. If &lt;code&gt;items.length === 0&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;, React renders the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag. If it's &lt;code&gt;false&lt;/code&gt;, React renders nothing. It's the JSX equivalent of an &lt;code&gt;if&lt;/code&gt; statement, inline.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Rendering a List with &lt;code&gt;.map()&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&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;item&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;li&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;p&gt;To render a list dynamically in React, you use &lt;code&gt;.map()&lt;/code&gt; to transform each array item into a JSX element.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;key&lt;/code&gt; prop is important — React uses it internally to track which items have changed, been added, or removed. Without it, you'll get a console warning and potentially buggy re-renders.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Dynamic CSS Classes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;selectdIndex&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list-group-item active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list-group-item&lt;/span&gt;&lt;span class="dl"&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 is a ternary operator used to conditionally apply a CSS class. If the current item's &lt;code&gt;index&lt;/code&gt; matches &lt;code&gt;selectdIndex&lt;/code&gt;, it gets the &lt;code&gt;active&lt;/code&gt; class (which highlights it in Bootstrap). Otherwise, it just gets the base class.&lt;/p&gt;

&lt;p&gt;It's a clean way to reflect state visually.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Handling Click Events
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setSelectedIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&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 list item is clicked, we call &lt;code&gt;setSelectedIndex(index)&lt;/code&gt; with the clicked item's index. React then re-renders the component with the new state, and the correct item gets the &lt;code&gt;active&lt;/code&gt; class.&lt;/p&gt;




&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;Here's the full picture of what happens when you use this component:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A parent component passes in an &lt;code&gt;items&lt;/code&gt; array and a &lt;code&gt;heading&lt;/code&gt; string&lt;/li&gt;
&lt;li&gt;The component renders the heading, an empty-state message (if needed), and the list&lt;/li&gt;
&lt;li&gt;When you click an item, &lt;code&gt;setSelectedIndex&lt;/code&gt; updates the state&lt;/li&gt;
&lt;li&gt;React re-renders, and the clicked item gets highlighted&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What I'd Improve Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fix the typo: &lt;code&gt;selectdIndex&lt;/code&gt; → &lt;code&gt;selectedIndex&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;&amp;lt;&amp;gt;...&amp;lt;/&amp;gt;&lt;/code&gt; shorthand instead of &lt;code&gt;&amp;lt;Fragment&amp;gt;&lt;/code&gt; (cleaner to read)&lt;/li&gt;
&lt;li&gt;Emit the selected item to the parent via an &lt;code&gt;onSelectItem&lt;/code&gt; callback prop — right now the selection is trapped inside the component&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;This small component taught me a lot: TypeScript interfaces, state management, conditional rendering, list rendering, and event handling — all in ~30 lines of code. React with TypeScript felt intimidating at first, but once you see how the pieces fit together, it starts to click.&lt;/p&gt;

&lt;p&gt;If you're also just starting out, I hope this breakdown helped. Let me know what you're building in the comments!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;#react&lt;/code&gt; &lt;code&gt;#typescript&lt;/code&gt; &lt;code&gt;#beginners&lt;/code&gt; &lt;code&gt;#webdev&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>react</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Designing TikTok from Scratch — A System Design Deep Dive</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Mon, 25 May 2026 22:24:05 +0000</pubDate>
      <link>https://dev.to/danikeya/designing-tiktok-from-scratch-a-system-design-deep-dive-57j8</link>
      <guid>https://dev.to/danikeya/designing-tiktok-from-scratch-a-system-design-deep-dive-57j8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Who is this for?&lt;/strong&gt; Mid-to-senior engineers preparing for system design interviews, or anyone curious how a short-video platform at billion-user scale actually works under the hood.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Scale We're Designing For
&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;Number&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monthly active users&lt;/td&gt;
&lt;td&gt;1B+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Videos uploaded per day&lt;/td&gt;
&lt;td&gt;~34 million&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target feed latency (P99)&lt;/td&gt;
&lt;td&gt;~167ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak egress bandwidth&lt;/td&gt;
&lt;td&gt;~26 Tbps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  1. Requirements
&lt;/h2&gt;

&lt;p&gt;Before drawing a single box, nail down what the system must do — and what it doesn't need to do perfectly on day one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Functional requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload and transcode short videos&lt;/li&gt;
&lt;li&gt;Serve a personalized "For You" feed&lt;/li&gt;
&lt;li&gt;Like, comment, share, follow&lt;/li&gt;
&lt;li&gt;Search videos and creators&lt;/li&gt;
&lt;li&gt;Live streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Non-functional requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High availability (99.99% uptime)&lt;/li&gt;
&lt;li&gt;Sub-200ms feed latency&lt;/li&gt;
&lt;li&gt;Horizontal scalability&lt;/li&gt;
&lt;li&gt;Global CDN video delivery&lt;/li&gt;
&lt;li&gt;Strong eventual consistency&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. High-Level Architecture
&lt;/h2&gt;

&lt;p&gt;The system splits into four major domains: &lt;strong&gt;ingestion&lt;/strong&gt; (upload pipeline), &lt;strong&gt;serving&lt;/strong&gt; (read path), &lt;strong&gt;recommendation&lt;/strong&gt; (ML feed), and &lt;strong&gt;social graph&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────┐
│              Mobile / Web Clients                │
└─────────────────────┬───────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────┐
│         Global CDN / Edge PoPs                   │
│   Video delivery, static assets, geo-routing    │
└─────────────────────┬───────────────────────────┘
                      │
┌─────────────────────▼───────────────────────────┐
│       API Gateway + Load Balancer                │
│   Auth, rate limiting, routing, TLS termination │
└────────┬────────────┴────────────────┬──────────┘
         │                             │
   ┌─────▼──────┐  ┌──────────────┐  ┌▼────────────────┐
   │  Upload    │  │ Feed Service │  │  Social Graph   │
   │  Service   │  │(pre-compute  │  │    Service      │
   │            │  │ + real-time) │  │                 │
   └─────┬──────┘  └──────┬───────┘  └┬────────────────┘
         │                │            │
   ┌─────▼──────┐  ┌──────▼───────┐  ┌▼────────────────┐
   │ Transcode  │  │Recommendation│  │  Notification   │
   │  Workers   │  │   Engine     │  │    Service      │
   └─────┬──────┘  └──────┬───────┘  └┬────────────────┘
         │                │            │
   ┌─────▼──────┐  ┌──────▼───────┐  ┌▼────────────────┐
   │  Object    │  │ Feature Store│  │  Search Service │
   │  Storage   │  │(Redis+Cassie)│  │ (Elasticsearch) │
   └─────┬──────┘  └──────┬───────┘  └┬────────────────┘
         │                │            │
┌────────▼────────────────▼────────────▼──────────────┐
│              Async Message Bus (Kafka)               │
└──────────┬──────────────┬──────────────┬────────────┘
           │              │              │
    ┌──────▼─────┐ ┌──────▼────┐ ┌──────▼──────┐
    │MySQL/Vitess│ │   Redis   │ │  Cassandra  │
    │(user data, │ │ (counters,│ │ (timelines, │
    │ metadata)  │ │  cache)   │ │  history)   │
    └────────────┘ └───────────┘ └─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;All services communicate asynchronously via Kafka for non-critical paths.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Key Components Explained
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CDN + Edge PoPs
&lt;/h3&gt;

&lt;p&gt;TikTok's secret weapon. &lt;strong&gt;~70% of video traffic&lt;/strong&gt; is served directly from edge nodes in 150+ cities, bypassing origin entirely. It uses Anycast routing to send users to the nearest PoP. Manifest files (playlist URLs) are invalidated within seconds of a video going viral.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upload Pipeline
&lt;/h3&gt;

&lt;p&gt;Chunked multi-part upload (5 MB chunks) tolerates flaky mobile connections. Workers dedup via &lt;code&gt;SHA-256&lt;/code&gt; before writing. Transcode jobs run on GPU fleets — outputs include &lt;code&gt;360p&lt;/code&gt;, &lt;code&gt;720p&lt;/code&gt;, &lt;code&gt;1080p&lt;/code&gt;, and HEVC variants. Thumbnails and stills are extracted for ML feature generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recommendation Engine
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;two-tower neural network&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tower 1&lt;/strong&gt; — encodes user state (watch history, device, time of day, location)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tower 2&lt;/strong&gt; — encodes video features (visual embeddings, audio, caption text)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dot product gives a relevance score. The model runs online for top-k retrieval, then a ranker applies real-time signals (trending, friend activity) before the feed is assembled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Feed Assembly (Pre-compute + Real-time Merge)
&lt;/h3&gt;

&lt;p&gt;This is where TikTok differs from Twitter/Instagram:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Celebrity/high-follow accounts&lt;/strong&gt; — fan-out on write (posts pushed to follower inboxes eagerly)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regular accounts&lt;/strong&gt; — fan-out on read (merged at request time)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The feed service merges both lists, injects ML-recommended videos, and applies diversity rules to avoid repetition. Final feed is cached in Redis with a &lt;code&gt;300s&lt;/code&gt; TTL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kafka Message Bus
&lt;/h3&gt;

&lt;p&gt;All write events (upload complete, like, follow, watch-complete) are published to Kafka topics. Downstream consumers include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Analytics pipeline&lt;/li&gt;
&lt;li&gt;Notification fan-out&lt;/li&gt;
&lt;li&gt;ML feature store updater&lt;/li&gt;
&lt;li&gt;Search indexer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Topics are partitioned by &lt;code&gt;user_id&lt;/code&gt; for ordered processing per user. This decouples services and allows independent scaling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database Strategy
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Store&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MySQL / Vitess&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;User profiles, video metadata, social graph&lt;/td&gt;
&lt;td&gt;ACID, sharded by &lt;code&gt;user_id&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redis Cluster&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Counters (likes, views), session tokens, feed cache&lt;/td&gt;
&lt;td&gt;Sub-millisecond reads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cassandra&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Watch history, timelines, notification logs&lt;/td&gt;
&lt;td&gt;Wide-row reads, high write throughput&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  4. Key Design Trade-offs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fan-out on Write vs Read
&lt;/h3&gt;

&lt;p&gt;The classic dilemma in social feed systems. TikTok uses a &lt;strong&gt;hybrid approach&lt;/strong&gt; (the "celebrity problem" split):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fan-out on write&lt;/strong&gt; (for accounts with millions of followers):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read path is O(1) — just read the inbox&lt;/li&gt;
&lt;li&gt;Fast feed assembly at serving time&lt;/li&gt;
&lt;li&gt;Massive write amplification when a celebrity posts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Fan-out on read&lt;/strong&gt; (for regular users):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No write amplification on post&lt;/li&gt;
&lt;li&gt;Storage-efficient&lt;/li&gt;
&lt;li&gt;Slower feed assembly if following thousands of accounts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Eventual vs Strong Consistency
&lt;/h3&gt;

&lt;p&gt;Like/view counts can lag by a few seconds — nobody notices. But user authentication tokens and billing events require &lt;strong&gt;strong consistency&lt;/strong&gt;. TikTok segments these into separate storage tiers with different consistency guarantees, accepting complexity for throughput on hot paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  Push vs Pull for Notifications
&lt;/h3&gt;

&lt;p&gt;Likes and comments use &lt;strong&gt;WebSocket push&lt;/strong&gt; for real-time delivery. Less critical notifications (weekly summaries, suggested follows) use a &lt;strong&gt;pull-based batch pipeline&lt;/strong&gt; that runs every few hours — no need to maintain a persistent connection for a weekly digest email.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Back-of-Envelope Estimates
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Assumptions:&lt;/strong&gt; 1B MAU, 500M DAU, avg user watches 45 min/day, avg video = 30 sec ~= 8 MB (720p). 34M uploads/day ~= 400 uploads/sec peak.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Storage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;34M uploads/day x 8 MB x 3 resolutions = ~816 TB/day of new video
With 3x replication over 5 years = ~4.4 EB total raw storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Feed reads:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;500M DAU x 20 feed refreshes/day / 86,400 sec = ~115,000 feed reads/sec
With 95% Redis cache hit rate -&amp;gt; recommendation backend sees ~5,750 rps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bandwidth:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;500M users x 45 min x 2 Mbps (720p) / 86,400 = ~26 Tbps peak egress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why TikTok operates its own backbone in many regions and has deep-peering agreements with major ISPs.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. What Makes TikTok's Architecture Special?
&lt;/h2&gt;

&lt;p&gt;Most social platforms optimize for social graph traversal — &lt;em&gt;show me what people I follow posted&lt;/em&gt;. TikTok inverted this: &lt;strong&gt;the algorithm is the product&lt;/strong&gt;. The architecture is built around a recommendation pipeline that must be both blazing-fast and constantly learning from watch signals.&lt;/p&gt;

&lt;p&gt;Three things stand out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Aggressive edge caching&lt;/strong&gt; — they push video delivery as close to the user as physically possible. The CDN is not a performance optimization; it is the entire delivery strategy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-time ML feedback loops&lt;/strong&gt; — a video's trajectory is decided in the first 30 minutes based on completion rate signals. A new creator can go viral without any followers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Microservice isolation&lt;/strong&gt; — upload, serving, recommendation, and social graph are independently deployable and scalable, preventing any single bottleneck from cascading.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Interview Tips
&lt;/h2&gt;

&lt;p&gt;If you're using this for a system design interview:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with requirements&lt;/strong&gt; — always clarify scale before designing anything&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estimate first&lt;/strong&gt; — back-of-envelope math shows you understand the constraints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sketch the high-level diagram&lt;/strong&gt; — then dive into the component your interviewer cares about&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talk through trade-offs&lt;/strong&gt; — interviewers want reasoning, not a list of technologies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bottleneck hunt&lt;/strong&gt; — proactively identify where the system will break and how you'd fix it&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Found this useful? Follow for more system design deep dives — next up: designing YouTube's upload pipeline at scale.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>architecture</category>
      <category>backend</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Two tiny functions that make your async code production-ready: `retry` and `timeout`</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Sun, 24 May 2026 00:01:00 +0000</pubDate>
      <link>https://dev.to/danikeya/two-tiny-functions-that-make-your-async-code-production-ready-retry-and-timeout-44e3</link>
      <guid>https://dev.to/danikeya/two-tiny-functions-that-make-your-async-code-production-ready-retry-and-timeout-44e3</guid>
      <description>&lt;p&gt;Every async function you write assumes the network cooperates, the server responds, and the database doesn't hiccup. In production, none of those assumptions hold forever.&lt;/p&gt;

&lt;p&gt;Here are two higher-order functions — each under 15 lines — that make any async function resilient without touching its internals.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;You have an async function. Maybe it calls an API, queries a database, or reads a file over the network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;Two things will go wrong eventually:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It will fail intermittently and you'll want to retry it&lt;/li&gt;
&lt;li&gt;It will hang indefinitely and you'll want to give up after a deadline&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You could wrap every function in retry logic and timeout logic inline. Or you could write it once, properly, and wrap any function you want.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;retry&lt;/code&gt; — automatic reattempts on failure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&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;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&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;await&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;lastError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;attempts&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;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;lastError&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;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;retry&lt;/code&gt; is a higher-order function — it takes a function and returns a new function with retry behaviour baked in. The original function is untouched.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;while (attempts &amp;lt;= count)&lt;/code&gt; condition is deliberate. If &lt;code&gt;count&lt;/code&gt; is &lt;code&gt;3&lt;/code&gt;, the loop runs when &lt;code&gt;attempts&lt;/code&gt; is &lt;code&gt;0, 1, 2, 3&lt;/code&gt; — that's 4 total executions: one initial attempt plus three retries. This matches the natural language meaning of "retry 3 times".&lt;/p&gt;

&lt;p&gt;On success, &lt;code&gt;return await callback(...args)&lt;/code&gt; exits immediately — no more iterations. On failure, the error is stored in &lt;code&gt;lastError&lt;/code&gt; and &lt;code&gt;attempts&lt;/code&gt; increments. Once the loop exhausts all attempts, the last error is rethrown — not a generic &lt;code&gt;new Error('Max retries reached')&lt;/code&gt;, but the actual error the callback produced. Your callers get a meaningful error message, not a wrapper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resilientFetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Works exactly like fetchUserData, but retries up to 3 times on failure&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;resilientFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why &lt;code&gt;await&lt;/code&gt; inside &lt;code&gt;try&lt;/code&gt; matters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&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;await&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ✓ catches rejected promises&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without &lt;code&gt;await&lt;/code&gt;, a rejected promise escapes the try/catch entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ✗ returns a pending promise — catch never fires&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;await&lt;/code&gt; unwraps the promise inside the try block, so rejections are catchable. This is one of the most common async/await mistakes and &lt;code&gt;retry&lt;/code&gt; only works correctly because it gets this right.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;timeout&lt;/code&gt; — give up after a deadline
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&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;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&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;timer&lt;/span&gt; &lt;span class="o"&gt;=&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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;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;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nx"&gt;delay&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;race&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;timer&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;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Promise.race&lt;/code&gt; resolves or rejects with whichever promise settles first. This function creates a race between two competitors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;callback(...args)&lt;/code&gt; — the actual work&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;timer&lt;/code&gt; — a promise that rejects after &lt;code&gt;delay&lt;/code&gt; milliseconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the callback finishes in time, its value wins and &lt;code&gt;timer&lt;/code&gt; becomes irrelevant. If &lt;code&gt;delay&lt;/code&gt; milliseconds pass first, &lt;code&gt;timer&lt;/code&gt; rejects with &lt;code&gt;Error('timeout')&lt;/code&gt; and the callback's eventual result is ignored.&lt;/p&gt;

&lt;p&gt;Notice the timer promise is constructed with &lt;code&gt;(_, reject)&lt;/code&gt; — it never resolves, only rejects. This ensures the timer can never accidentally win the race with a successful value; it can only interrupt with a failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limitedFetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;try&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;limitedFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_123&lt;/span&gt;&lt;span class="dl"&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;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request took too long&lt;/span&gt;&lt;span class="dl"&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;h2&gt;
  
  
  Combining them
&lt;/h2&gt;

&lt;p&gt;Both functions return async functions with the same signature as their input — which means they compose cleanly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Retry up to 3 times, but abandon any single attempt after 5 seconds&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resilientFetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchUserData&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;resilientFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what happens on each attempt:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;timeout(5000, fetchUserData)&lt;/code&gt; races the fetch against a 5-second timer&lt;/li&gt;
&lt;li&gt;If it times out, &lt;code&gt;timeout&lt;/code&gt; rejects with &lt;code&gt;Error('timeout')&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;retry&lt;/code&gt; catches that rejection, increments attempts, and tries again&lt;/li&gt;
&lt;li&gt;After 3 retries all fail, &lt;code&gt;retry&lt;/code&gt; rethrows the last error&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Four attempts, each with a 5-second ceiling, maximum 20 seconds total. All from two composable functions and one line of setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  What makes these worth keeping
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;They don't modify the original function.&lt;/strong&gt; &lt;code&gt;fetchUserData&lt;/code&gt; is unchanged. You can use it with or without retry/timeout anywhere else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They forward arguments transparently.&lt;/strong&gt; &lt;code&gt;...args&lt;/code&gt; passes everything through — the wrapped function behaves identically to the original from the caller's perspective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They preserve the error.&lt;/strong&gt; &lt;code&gt;retry&lt;/code&gt; rethrows &lt;code&gt;lastError&lt;/code&gt;, not a new generic error. &lt;code&gt;timeout&lt;/code&gt; rejects with a named &lt;code&gt;Error('timeout')&lt;/code&gt; you can check by message. Callers always know what actually went wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They compose.&lt;/strong&gt; Because both return async functions with matching signatures, you can layer them in any order and they work together without knowing about each other.&lt;/p&gt;




&lt;h2&gt;
  
  
  The pattern
&lt;/h2&gt;

&lt;p&gt;Both functions follow the same structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;higherOrderFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&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;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// enhanced behaviour around callback(...args)&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 is the decorator pattern applied to async functions. You write the enhancement once, and apply it to any async function that needs it — no inheritance, no classes, no modification of the original. Just functions wrapping functions.&lt;/p&gt;

&lt;p&gt;It's a small pattern. It shows up everywhere once you start looking for it.&lt;/p&gt;




</description>
      <category>javascript</category>
      <category>web</category>
    </item>
    <item>
      <title>When async functions tell stories: dissecting a real-world JavaScript code review</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Sat, 23 May 2026 23:55:39 +0000</pubDate>
      <link>https://dev.to/danikeya/when-async-functions-tell-stories-dissecting-a-real-world-javascript-code-review-46hn</link>
      <guid>https://dev.to/danikeya/when-async-functions-tell-stories-dissecting-a-real-world-javascript-code-review-46hn</guid>
      <description>&lt;p&gt;You're reviewing a teammate's pull request. The function looks fine at first glance — it's async, it has a try/catch, it returns strings. Then you look closer and realise it has a bug that will silently swallow errors and return the wrong thing in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's walk through it.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&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;country&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; never was a winner`&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;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;continent&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Europe&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is not what we are looking for because of the continent`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;results&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Results Not Found&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; never was a winner`&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;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is not what we are looking for because of the number of times it was champion`&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; won the FIFA World Cup in `&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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; winning by &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&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;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; never was a winner`&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function queries a database for a country's FIFA World Cup wins. It checks if a country exists, if it's in Europe, if it won at least 3 times, and then formats the results.&lt;/p&gt;

&lt;p&gt;Reasonable goal. Shaky execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bug #1: comparing errors with &lt;code&gt;===&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&lt;/span&gt;&lt;span class="dl"&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;This will &lt;strong&gt;never be true&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Error('Country Not Found')&lt;/code&gt; creates a brand new Error object every time it's called. In JavaScript, objects are compared by reference, not by value. So &lt;code&gt;country === Error('Country Not Found')&lt;/code&gt; is asking "is &lt;code&gt;country&lt;/code&gt; the exact same object in memory as this new Error I just created?" — and the answer is always no.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false — different objects&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same bug appears further down with &lt;code&gt;results === Error('Results Not Found')&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What was probably intended:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The database likely throws when a country isn't found, rather than returning an Error object. In that case, the catch block handles it. If the db genuinely returns an Error instance, the correct check is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&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="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// or&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;country&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&lt;/span&gt;&lt;span class="dl"&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Bug #2: overwriting the parameter
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ← overwrites the input&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function receives &lt;code&gt;country&lt;/code&gt; as a string (e.g. &lt;code&gt;"Brazil"&lt;/code&gt;), then immediately reassigns it to the database result object. This is why the catch block has to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; never was a winner`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// country is now an object, not a string&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;If &lt;code&gt;db.getWinner&lt;/code&gt; throws before assigning, &lt;code&gt;country&lt;/code&gt; is still the original string — fine. But if it throws &lt;em&gt;after&lt;/em&gt; a partial assignment, &lt;code&gt;country&lt;/code&gt; could be anything. And if &lt;code&gt;db.getResults&lt;/code&gt; throws, &lt;code&gt;country&lt;/code&gt; is already the database object, so &lt;code&gt;${country}&lt;/code&gt; would render as &lt;code&gt;[object Object] never was a winner&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; use a separate variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countryName&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;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countryName&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;h2&gt;
  
  
  Bug #3: the catch block returns &lt;code&gt;undefined&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; never was a winner`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// what happens here?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the error is anything &lt;em&gt;other&lt;/em&gt; than &lt;code&gt;'Country Not Found'&lt;/code&gt; — a network failure, a malformed response, a typo in the db call — the &lt;code&gt;if&lt;/code&gt; condition is false and the catch block falls through without returning anything. The function returns &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The caller gets back &lt;code&gt;undefined&lt;/code&gt; with no indication that something went wrong. No rethrow, no fallback message, silent failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; always handle the unexpected case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;countryName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; never was a winner`&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;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// let unexpected errors propagate&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A cleaner version
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countryName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getWinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;countryName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country Not Found&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;countryName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; never was a winner`&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;e&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;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;continent&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Europe&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is not what we are looking for because of the continent`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Results Not Found&lt;/span&gt;&lt;span class="dl"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; never was a winner`&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;e&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;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is not what we are looking for because of the number of times it was champion`&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; won the FIFA World Cup in `&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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; winning by &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="dl"&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;Each async operation gets its own try/catch scoped to its own error. The parameter is never overwritten. Unexpected errors are rethrown rather than swallowed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Never compare Error objects with &lt;code&gt;===&lt;/code&gt;.&lt;/strong&gt; Errors are objects — two errors with the same message are not the same object. Use &lt;code&gt;instanceof Error&lt;/code&gt; or check &lt;code&gt;.message&lt;/code&gt; on a caught error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Don't reuse parameters as working variables.&lt;/strong&gt; The moment you reassign a parameter, you lose the original value everywhere — including the catch block where you might need it most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. A catch block that doesn't rethrow is a promise to handle everything.&lt;/strong&gt; If you only handle one specific error and silently drop the rest, you're hiding bugs. Either handle all cases or rethrow what you can't handle.&lt;/p&gt;




&lt;p&gt;Code review isn't about finding someone to blame. It's about finding the bugs before users do. This one had three of them hiding in plain sight behind reasonable-looking syntax.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;javascript&lt;/code&gt; &lt;code&gt;async&lt;/code&gt; &lt;code&gt;debugging&lt;/code&gt; &lt;code&gt;codereview&lt;/code&gt; &lt;code&gt;webdev&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Shared-Key Cryptosystems in JavaScript: A Practical Guide</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Thu, 21 May 2026 18:33:33 +0000</pubDate>
      <link>https://dev.to/danikeya/shared-key-cryptosystems-in-javascript-a-practical-guide-4h63</link>
      <guid>https://dev.to/danikeya/shared-key-cryptosystems-in-javascript-a-practical-guide-4h63</guid>
      <description>&lt;p&gt;Cryptography sounds intimidating — but once you understand the core idea behind &lt;strong&gt;shared-key (symmetric) cryptosystems&lt;/strong&gt;, you'll wonder why you ever found it mysterious. In this post, we'll break down what it is, how it works, and how to implement it practically in JavaScript using the &lt;strong&gt;Web Crypto API&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is a Shared-Key Cryptosystem?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;shared-key cryptosystem&lt;/strong&gt; (also called a &lt;em&gt;symmetric-key&lt;/em&gt; cryptosystem) is one where &lt;strong&gt;the same key is used to both encrypt and decrypt&lt;/strong&gt; data. Think of it like a physical padlock — whoever has the key can lock &lt;em&gt;and&lt;/em&gt; unlock it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plaintext → [ Encrypt with Key K ] → Ciphertext → [ Decrypt with Key K ] → Plaintext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is in contrast to &lt;strong&gt;asymmetric cryptography&lt;/strong&gt; (like RSA), which uses a public/private key pair. Symmetric encryption is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Fast&lt;/strong&gt; — ideal for large amounts of data&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Efficient&lt;/strong&gt; — lower computational overhead&lt;/li&gt;
&lt;li&gt;⚠️ &lt;strong&gt;Key distribution problem&lt;/strong&gt; — both parties must securely share the same key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Popular shared-key algorithms include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AES&lt;/strong&gt; (Advanced Encryption Standard) — the gold standard today&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ChaCha20&lt;/strong&gt; — modern, fast, used in TLS 1.3&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3DES&lt;/strong&gt; — legacy, being phased out&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Key Exchange Problem
&lt;/h2&gt;

&lt;p&gt;Here's the fundamental challenge: if Alice and Bob want to communicate secretly using a shared key, &lt;strong&gt;how do they exchange that key without Eve intercepting it?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Alice ──── "Here's our secret key!" ────→   Eve intercepts  ──→ Bob
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is solved in practice by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Diffie-Hellman key exchange&lt;/strong&gt; — mathematically derive a shared secret over a public channel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asymmetric encryption&lt;/strong&gt; — encrypt the symmetric key with a public key, then decrypt with a private key (hybrid encryption, used in TLS)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For this post, we'll focus on the &lt;strong&gt;encryption/decryption mechanics&lt;/strong&gt; assuming the key is already securely shared.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hands-On: AES-GCM in JavaScript
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Web Crypto API&lt;/strong&gt; (&lt;code&gt;window.crypto.subtle&lt;/code&gt;) is built into modern browsers and Node.js 18+. It gives us access to AES-GCM — &lt;strong&gt;AES in Galois/Counter Mode&lt;/strong&gt; — which provides both &lt;strong&gt;encryption and authentication&lt;/strong&gt; (it detects tampering).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Generate a Shared Key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateKey&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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 256-bit key — strong!&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;// extractable: allows export&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;encrypt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decrypt&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;key&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;sharedKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Key generated:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sharedKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Encrypt a Message
&lt;/h3&gt;

&lt;p&gt;AES-GCM requires a &lt;strong&gt;random IV (Initialization Vector)&lt;/strong&gt; for every encryption. The IV doesn't need to be secret — just unique per operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;plaintext&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;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 96-bit IV for AES-GCM&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encodedText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plaintext&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;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;encodedText&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Return both IV and ciphertext — the IV is needed for decryption&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, Bob! This is our secret message. &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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sharedKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Encrypted:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why bundle the IV with the ciphertext?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The IV is required for decryption. It's not secret — it just must be unique. Sending it alongside the ciphertext is standard practice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3: Decrypt the Message
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&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;decryptedBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;ciphertext&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;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decryptedBuffer&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;decryptedMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sharedKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Decrypted:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decryptedMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// → "Hello, Bob! This is our secret message. "&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Exporting and Importing Keys
&lt;/h2&gt;

&lt;p&gt;In real applications, you'll need to &lt;strong&gt;serialize the key&lt;/strong&gt; — to send it over a wire, store it in a database, or share it between sessions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Export the key to raw bytes&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;exportKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&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;exported&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exportKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;raw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&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;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exported&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Import raw bytes back into a CryptoKey&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;importKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawKeyBytes&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;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;importKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;raw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;rawKeyBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;encrypt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decrypt&lt;/span&gt;&lt;span class="dl"&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;exportKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sharedKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Raw key bytes:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rawKey&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;importedKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;importKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawKey&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;testDecrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;importedKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Decrypted with imported key:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;testDecrypt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ✅ Still works!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Putting It All Together: A Complete Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ============================================================&lt;/span&gt;
&lt;span class="c1"&gt;// Shared-Key Cryptosystem Demo — AES-GCM with Web Crypto API&lt;/span&gt;
&lt;span class="c1"&gt;// ============================================================&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;generateKey&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;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;encrypt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decrypt&lt;/span&gt;&lt;span class="dl"&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;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;plaintext&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;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&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;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plaintext&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;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;encoded&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="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&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;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AES-GCM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;ciphertext&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;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&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;// --- Simulation ---&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="c1"&gt;// Alice and Bob agree on a shared key (assume secure exchange)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sharedKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Alice encrypts&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The treasure is buried under the old oak tree. 🌳&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sharedKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alice sends encrypted message.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Bob decrypts&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;revealed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sharedKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob reads:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;revealed&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;
  
  
  Security Considerations ⚠️
&lt;/h2&gt;

&lt;p&gt;Before you ship anything crypto-related, keep these in mind:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Practice&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Never reuse an IV&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reusing an IV with the same key completely breaks AES-GCM security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use AES-GCM over AES-CBC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GCM provides authentication; CBC does not (vulnerable to padding oracle attacks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Don't roll your own crypto&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stick to well-audited APIs like Web Crypto&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Key length: 256-bit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;128-bit is technically secure, but 256-bit is the modern standard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Protect your keys&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An encrypted message is only as safe as the key protecting it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  When to Use Shared-Key vs. Asymmetric Cryptography
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Shared-Key (Symmetric)&lt;/th&gt;
&lt;th&gt;Asymmetric&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very fast&lt;/td&gt;
&lt;td&gt;Slow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Key management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Single shared secret&lt;/td&gt;
&lt;td&gt;Public/private pair&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bulk data encryption&lt;/td&gt;
&lt;td&gt;Key exchange, digital signatures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AES, ChaCha20&lt;/td&gt;
&lt;td&gt;RSA, ECC&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In practice, most systems use &lt;strong&gt;both&lt;/strong&gt;: asymmetric crypto to securely exchange a symmetric key, then symmetric crypto for the actual data. This is exactly how &lt;strong&gt;TLS/HTTPS&lt;/strong&gt; works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Here's what we covered:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Shared-key cryptosystems&lt;/strong&gt; use the same key to encrypt and decrypt&lt;/li&gt;
&lt;li&gt; They're &lt;strong&gt;fast and efficient&lt;/strong&gt;, ideal for bulk data&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Web Crypto API&lt;/strong&gt; gives you production-grade AES-GCM in the browser and Node.js&lt;/li&gt;
&lt;li&gt; Always use a &lt;strong&gt;random, unique IV&lt;/strong&gt; per encryption&lt;/li&gt;
&lt;li&gt;🔐 &lt;strong&gt;Never reuse IVs&lt;/strong&gt;, and never build your own crypto primitives&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cryptography in JavaScript has never been more accessible — and with the Web Crypto API, you have no excuse to use weak homebrew solutions. Go build something secure! &lt;/p&gt;




&lt;p&gt;&lt;em&gt;Found this helpful? Drop a ❤️ or leave a comment below. Got questions about key exchange or asymmetric crypto? Let me know — that's a great follow-up post topic!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>cryptography</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Go Backend Frameworks: Which One Should You Actually Use?</title>
      <dc:creator>Daniel Keya</dc:creator>
      <pubDate>Thu, 21 May 2026 02:25:23 +0000</pubDate>
      <link>https://dev.to/danikeya/go-backend-frameworks-which-one-should-you-actually-use-n0n</link>
      <guid>https://dev.to/danikeya/go-backend-frameworks-which-one-should-you-actually-use-n0n</guid>
      <description>&lt;p&gt;Go ships with one of the most capable standard libraries of any modern language. &lt;code&gt;net/http&lt;/code&gt; alone can take you surprisingly far — but the ecosystem has grown a rich set of frameworks and routers that sit on top of it, each with a different philosophy.&lt;/p&gt;

&lt;p&gt;In this post we'll walk through the five most popular options, compare them honestly, and land on a recommendation based on what you're actually building.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Contenders
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;GitHub Stars&lt;/th&gt;
&lt;th&gt;Philosophy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;net/http&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;(stdlib)&lt;/td&gt;
&lt;td&gt;Zero dependencies, full control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gin&lt;/td&gt;
&lt;td&gt;77k+&lt;/td&gt;
&lt;td&gt;Fast, minimal, huge ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Echo&lt;/td&gt;
&lt;td&gt;29k+&lt;/td&gt;
&lt;td&gt;Clean API, great middleware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fiber&lt;/td&gt;
&lt;td&gt;33k+&lt;/td&gt;
&lt;td&gt;Express.js-inspired, fastest benchmarks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chi&lt;/td&gt;
&lt;td&gt;18k+&lt;/td&gt;
&lt;td&gt;Lightweight router, stdlib-compatible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  1. &lt;code&gt;net/http&lt;/code&gt; — The Standard Library
&lt;/h2&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;"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;http&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;"/"&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;"Hello, World!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&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="no"&gt;nil&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;Go's built-in HTTP package is more capable than most developers give it credit for. No install, no version conflicts, no breaking changes between releases — it ships with Go itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams that know Go well and want zero dependencies&lt;/li&gt;
&lt;li&gt;Long-lived projects where stability matters more than convenience&lt;/li&gt;
&lt;li&gt;Microservices where keeping the binary small is a priority&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Watch out for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No built-in router with path parameters (&lt;code&gt;/users/:id&lt;/code&gt;) — you'll write that yourself or pull in a package&lt;/li&gt;
&lt;li&gt;Middleware chaining is manual and can get verbose&lt;/li&gt;
&lt;li&gt;No built-in JSON binding or validation helpers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Gin — The Industry Standard
&lt;/h2&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="s"&gt;"github.com/gin-gonic/gin"&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;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&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;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/:id"&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;gin&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;id&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;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&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;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&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;Run&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gin is the most widely used Go web framework by a significant margin. It gives you path parameters, JSON binding, validation, middleware, and group routing out of the box — all with benchmark numbers that rival raw &lt;code&gt;net/http&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST APIs where you want to move fast&lt;/li&gt;
&lt;li&gt;Teams new to Go who want familiar patterns and good documentation&lt;/li&gt;
&lt;li&gt;Projects where community support and third-party middleware matter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Watch out for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context is Gin's own &lt;code&gt;*gin.Context&lt;/code&gt;, not the stdlib &lt;code&gt;context.Context&lt;/code&gt; — some packages expect the latter&lt;/li&gt;
&lt;li&gt;Middleware can grow tangled in large codebases if you're not deliberate about structure&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;gin.H&lt;/code&gt; shorthand is convenient but easy to overuse at the cost of type safety&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Echo — The Clean Alternative
&lt;/h2&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;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/labstack/echo/v4"&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;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/:id"&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="n"&gt;echo&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="n"&gt;id&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;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&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="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="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Echo and Gin are often compared head to head. Echo's API is slightly more consistent — handlers return an &lt;code&gt;error&lt;/code&gt;, which is more idiomatic Go than Gin's &lt;code&gt;c.JSON()&lt;/code&gt; pattern. The built-in middleware is well-designed and the docs are excellent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams who like Gin's speed but want a cleaner, more idiomatic API&lt;/li&gt;
&lt;li&gt;Projects that need strong built-in middleware (CORS, JWT, rate limiting)&lt;/li&gt;
&lt;li&gt;Developers who care about error handling being a first-class citizen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Watch out for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller community than Gin — fewer third-party plugins and Stack Overflow answers&lt;/li&gt;
&lt;li&gt;Slightly steeper learning curve for beginners coming from other languages&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Fiber — The Express.js Port
&lt;/h2&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="s"&gt;"github.com/gofiber/fiber/v2"&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;app&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fiber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/:id"&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;fiber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ctx&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="n"&gt;id&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;Params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fiber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Listen&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've built APIs in Node.js with Express, Fiber will feel immediately familiar. It mirrors Express's API almost exactly — same method names, same patterns, same philosophy. Under the hood it uses &lt;code&gt;fasthttp&lt;/code&gt; instead of &lt;code&gt;net/http&lt;/code&gt;, which is why its benchmarks sit at the top of most comparisons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers migrating from Node.js/Express who want a gentle transition&lt;/li&gt;
&lt;li&gt;High-throughput services where raw performance is the primary concern&lt;/li&gt;
&lt;li&gt;Projects that don't need to interop with the &lt;code&gt;net/http&lt;/code&gt; ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Watch out for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fasthttp&lt;/code&gt; is not compatible with &lt;code&gt;net/http&lt;/code&gt; — packages that expect a standard &lt;code&gt;http.Handler&lt;/code&gt; won't work&lt;/li&gt;
&lt;li&gt;Less idiomatic Go — the API optimises for familiarity over correctness&lt;/li&gt;
&lt;li&gt;Smaller ecosystem than Gin for middleware and plugins&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Chi — The Minimal Router
&lt;/h2&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;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/go-chi/chi/v5"&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;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;chi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&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;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{id}"&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;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;chi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URLParam&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;span class="s"&gt;"id"&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;Fprintf&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;"User: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&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;r&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;Chi is not a framework — it's a router. It sits directly on top of &lt;code&gt;net/http&lt;/code&gt; and uses standard &lt;code&gt;http.Handler&lt;/code&gt; and &lt;code&gt;http.HandlerFunc&lt;/code&gt; interfaces throughout. You bring your own middleware, your own JSON helpers, your own everything. What you get is a clean, composable routing layer with no surprises.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams that want routing structure without committing to a full framework&lt;/li&gt;
&lt;li&gt;Projects that need full &lt;code&gt;net/http&lt;/code&gt; compatibility&lt;/li&gt;
&lt;li&gt;Developers who prefer assembling tools over adopting opinions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Watch out for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're responsible for wiring together everything Gin and Echo give you for free&lt;/li&gt;
&lt;li&gt;More upfront setup — not ideal when you need to move fast&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Head-to-Head Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;net/http&lt;/th&gt;
&lt;th&gt;Gin&lt;/th&gt;
&lt;th&gt;Echo&lt;/th&gt;
&lt;th&gt;Fiber&lt;/th&gt;
&lt;th&gt;Chi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Community&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;stdlib compat&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Middleware&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Idiomatic Go&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  My Pick
&lt;/h2&gt;

&lt;p&gt;There is no single best answer — but here's how I actually choose:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;→ Building a REST API and want to move fast?&lt;/strong&gt; Use &lt;strong&gt;Gin&lt;/strong&gt;. The ecosystem is massive, the docs are good, and you'll find answers to every problem you hit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;→ Want Gin's speed with cleaner, more idiomatic code?&lt;/strong&gt; Use &lt;strong&gt;Echo&lt;/strong&gt;. The error-return pattern is more Go-like and the built-in middleware is excellent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;→ Coming from Node.js/Express?&lt;/strong&gt; Use &lt;strong&gt;Fiber&lt;/strong&gt; to get productive immediately — then consider migrating to something more idiomatic once you're comfortable with Go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;→ Want full control with minimal dependencies?&lt;/strong&gt; Use &lt;strong&gt;Chi&lt;/strong&gt; for routing and bolt on exactly what you need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;→ Building something you'll maintain for years with a Go-fluent team?&lt;/strong&gt; Use &lt;strong&gt;net/http&lt;/strong&gt; directly. It'll outlast every framework on this list.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest Truth
&lt;/h2&gt;

&lt;p&gt;Most Go backend performance debates are irrelevant at the scale most of us actually operate at. Gin, Echo, and Fiber all handle tens of thousands of requests per second on modest hardware. The framework won't be your bottleneck — your database will.&lt;/p&gt;

&lt;p&gt;Pick based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What your team already knows&lt;/li&gt;
&lt;li&gt;How much you value idiomatic Go vs developer ergonomics&lt;/li&gt;
&lt;li&gt;Whether you need &lt;code&gt;net/http&lt;/code&gt; compatibility&lt;/li&gt;
&lt;li&gt;How long you plan to maintain this&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best Go framework is the one your team can understand, extend, and debug at 2am without wanting to quit.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Your Pick?
&lt;/h2&gt;

&lt;p&gt;Every Go developer has an opinion on this. Are you a Gin loyalist? A stdlib purist? Did Fiber win you over from Node.js?&lt;/p&gt;

&lt;p&gt;Drop it in the comments — I'd love to know what you're running in production and why.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written with ❤️ in Go&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you enjoyed this, feel free to check out more of my work on GitHub 👉 &lt;a href="https://github.com/keyadaniel56" rel="noopener noreferrer"&gt;keyadaniel56&lt;/a&gt; — always building something new in Go and beyond.&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
