<?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: Ansh Dhanani</title>
    <description>The latest articles on DEV Community by Ansh Dhanani (@dhanani_ansh).</description>
    <link>https://dev.to/dhanani_ansh</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%2F3564462%2F02a3303b-8c66-485a-b462-269e8c667736.jpg</url>
      <title>DEV Community: Ansh Dhanani</title>
      <link>https://dev.to/dhanani_ansh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dhanani_ansh"/>
    <language>en</language>
    <item>
      <title>Distributed Systems and Raft Consensus</title>
      <dc:creator>Ansh Dhanani</dc:creator>
      <pubDate>Fri, 09 Oct 2026 17:53:34 +0000</pubDate>
      <link>https://dev.to/dhanani_ansh/distributed-systems-and-raft-consensus-24c3</link>
      <guid>https://dev.to/dhanani_ansh/distributed-systems-and-raft-consensus-24c3</guid>
      <description>&lt;p&gt;A single process is relatively easy to reason about. It has one memory space, one execution flow, and usually one place to inspect when something goes wrong.&lt;/p&gt;

&lt;p&gt;Now put the application on several machines. They communicate over a network, store copies of data, and keep serving requests while machines restart or connections fail. You get more capacity and potentially better availability, but you also get a new set of problems: messages can be delayed, machines can disappear, and two nodes can disagree about what happened.&lt;/p&gt;

&lt;p&gt;now, for anyone first time, It can be tough to visualize how this actually works in practice, but don't worry we will break it all down step by step. By the end of this guide, you won't need to look anywhere else.&lt;/p&gt;

&lt;p&gt;This is the world of distributed systems.&lt;/p&gt;

&lt;p&gt;Raft is one way to solve a particularly important part of that problem: getting a group of machines to agree on an ordered sequence of changes, even when some machines fail.&lt;/p&gt;

&lt;p&gt;The central problem is not making every machine identical at every instant. It is making the system behave consistently despite delays and failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. What is a distributed system?&lt;/li&gt;
&lt;li&gt;2. Why distributed systems are hard&lt;/li&gt;
&lt;li&gt;3. Common distributed system building blocks&lt;/li&gt;
&lt;li&gt;4. Replication and consistency&lt;/li&gt;
&lt;li&gt;5. The CAP theorem&lt;/li&gt;
&lt;li&gt;6. What is consensus?&lt;/li&gt;
&lt;li&gt;7. Why Raft?&lt;/li&gt;
&lt;li&gt;8. Raft cluster architecture&lt;/li&gt;
&lt;li&gt;9. Leader election&lt;/li&gt;
&lt;li&gt;10. Log replication&lt;/li&gt;
&lt;li&gt;11. Terms, log matching, and safety&lt;/li&gt;
&lt;li&gt;12. Committing entries&lt;/li&gt;
&lt;li&gt;13. Client requests and linearizability&lt;/li&gt;
&lt;li&gt;14. What happens when nodes fail?&lt;/li&gt;
&lt;li&gt;15. Snapshots and log compaction&lt;/li&gt;
&lt;li&gt;16. Membership changes&lt;/li&gt;
&lt;li&gt;17. A worked example&lt;/li&gt;
&lt;li&gt;18. Raft versus other approaches&lt;/li&gt;
&lt;li&gt;19. Where Raft is used&lt;/li&gt;
&lt;li&gt;20. Observability and debugging&lt;/li&gt;
&lt;li&gt;21. Common mistakes&lt;/li&gt;
&lt;li&gt;22. Quick reference&lt;/li&gt;
&lt;li&gt;23. Further reading&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. What is a distributed system?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;distributed system&lt;/strong&gt; is a collection of independent computers that communicate over a network and cooperate to provide a service.&lt;/p&gt;

&lt;p&gt;Each machine has its own CPU, memory, operating system, and local view of the world. There is no single shared clock or shared memory that all machines can access instantly.&lt;/p&gt;

&lt;p&gt;A simple example is a web application with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A load balancer receiving incoming requests.&lt;/li&gt;
&lt;li&gt;Several application servers processing them.&lt;/li&gt;
&lt;li&gt;A database storing application data.&lt;/li&gt;
&lt;li&gt;A cache reducing repeated database work.&lt;/li&gt;
&lt;li&gt;A message broker handling background jobs.&lt;/li&gt;
&lt;li&gt;Monitoring services collecting metrics and logs.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                     Users
                       |
                       v
                 Load Balancer
                  /    |    \
                 v     v     v
              App A  App B  App C
                 \     |     /
                  \    |    /
                   v   v   v
                  Database
                      |
                      v
                 Persistent Disk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These components run separately, but together they provide one application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not use one powerful machine?
&lt;/h3&gt;

&lt;p&gt;A single machine can be a sensible starting point. Distributed systems add complexity, so distributing everything without a reason is usually a bad trade.&lt;/p&gt;

&lt;p&gt;Multiple machines can help when you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More capacity:&lt;/strong&gt; split work across several machines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fault tolerance:&lt;/strong&gt; keep serving requests when a machine fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geographic distribution:&lt;/strong&gt; place services closer to users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation:&lt;/strong&gt; separate workloads with different resource needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent scaling:&lt;/strong&gt; scale a busy component without scaling everything else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But adding machines does not automatically make a system reliable. It introduces network failures, coordination, partial failures, replication lag, and operational overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  The important idea: partial failure
&lt;/h3&gt;

&lt;p&gt;In a local program, if a function returns, throws an exception, or crashes, the process can often determine what happened.&lt;/p&gt;

&lt;p&gt;In a distributed system, a request may be sent to another machine and then time out. The caller cannot immediately know whether:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The remote machine never received the request.&lt;/li&gt;
&lt;li&gt;The machine received it but has not processed it yet.&lt;/li&gt;
&lt;li&gt;The machine processed it, but the response was lost.&lt;/li&gt;
&lt;li&gt;The machine crashed during processing.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client                 Server
  |                       |
  |------ Request -------&amp;gt;|
  |                       | Process request
  |                       | Save result
  |&amp;lt;----- Response -------X  Response lost
  |
  | Timeout
  |
  | "Did the operation happen?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client sees a timeout. The server may have completed the operation successfully.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;partial failure&lt;/strong&gt;: one part of the system cannot tell whether another part is working, failed, or simply slow.&lt;/p&gt;

&lt;p&gt;A timeout is evidence that a response did not arrive in time. It is not proof that the operation did not happen.&lt;/p&gt;

&lt;p&gt;This distinction matters for payments, job processing, database writes, and any operation that should not be performed twice.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Why distributed systems are hard
&lt;/h2&gt;

&lt;p&gt;The hard part is not sending a message. The hard part is deciding what to do when messages and machines do not behave as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network delay is unpredictable
&lt;/h3&gt;

&lt;p&gt;A message might arrive in milliseconds, arrive much later, or never arrive because a connection has broken. A slow network can look similar to a failed machine.&lt;/p&gt;

&lt;p&gt;There is no universal timeout that perfectly distinguishes a slow node from a dead node. A short timeout detects failures quickly but may trigger unnecessary elections. A long timeout avoids some false suspicions but delays recovery.&lt;/p&gt;

&lt;h3&gt;
  
  
  Machines can fail independently
&lt;/h3&gt;

&lt;p&gt;Consider a cluster with three nodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node A: healthy
Node B: crashed
Node C: healthy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cluster may continue operating if its protocol permits a majority of nodes to make progress.&lt;/p&gt;

&lt;p&gt;Now consider a network partition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Partition
   A --------X-------- B
   |                   |
   |                   |
   C                   D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nodes on one side may communicate normally with each other but cannot reach the other side. Both sides might believe the other side has failed.&lt;/p&gt;

&lt;p&gt;A safe protocol must prevent both sides from independently making conflicting decisions that are treated as committed.&lt;/p&gt;

&lt;h3&gt;
  
  
  There is no perfect global clock
&lt;/h3&gt;

&lt;p&gt;Machine A's clock can differ from Machine B's clock. Even if both clocks are synchronized periodically, there can be drift and synchronization error.&lt;/p&gt;

&lt;p&gt;Therefore, timestamps alone are not a reliable way to establish the exact order of events across machines.&lt;/p&gt;

&lt;p&gt;Distributed systems often use logical ordering, such as sequence numbers, log indexes, and protocol terms, to reason about events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Messages can be duplicated or reordered
&lt;/h3&gt;

&lt;p&gt;Depending on the protocol and retry behavior, a request may be retried after a timeout. An application may receive the same logical operation more than once.&lt;/p&gt;

&lt;p&gt;A robust design may need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request identifiers.&lt;/li&gt;
&lt;li&gt;Idempotency keys.&lt;/li&gt;
&lt;li&gt;Deduplication records.&lt;/li&gt;
&lt;li&gt;Sequence numbers.&lt;/li&gt;
&lt;li&gt;Explicit ordering rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The system has more than one state
&lt;/h3&gt;

&lt;p&gt;A distributed application may have several different notions of state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local memory on each process.&lt;/li&gt;
&lt;li&gt;Durable state on disk.&lt;/li&gt;
&lt;li&gt;Replicated state on other nodes.&lt;/li&gt;
&lt;li&gt;The state currently visible to clients.&lt;/li&gt;
&lt;li&gt;State held by caches or downstream services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These states may temporarily differ. The protocol must define which differences are allowed and when a change becomes authoritative.&lt;/p&gt;

&lt;h3&gt;
  
  
  Safety and liveness
&lt;/h3&gt;

&lt;p&gt;These two terms appear throughout distributed systems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Safety&lt;/td&gt;
&lt;td&gt;Nothing bad happens&lt;/td&gt;
&lt;td&gt;Two leaders do not commit conflicting values for the same log position&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Liveness&lt;/td&gt;
&lt;td&gt;Something good eventually happens&lt;/td&gt;
&lt;td&gt;A healthy majority can elect a leader and make progress&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A protocol can preserve safety by refusing to do anything when it cannot establish agreement. That may be correct but unavailable.&lt;/p&gt;

&lt;p&gt;A protocol that always accepts writes may remain responsive but risk conflicting histories.&lt;/p&gt;

&lt;p&gt;Good distributed protocols define which guarantees they preserve and under what assumptions.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Common distributed system building blocks
&lt;/h2&gt;

&lt;p&gt;Consensus is important, but it is only one tool in a larger toolbox.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load balancing
&lt;/h3&gt;

&lt;p&gt;A load balancer distributes requests across multiple servers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Request
                |
                v
          Load Balancer
           /    |    \
          v     v     v
        App A  App B  App C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Load balancing can improve capacity and availability, but it does not automatically synchronize application state. If App A stores a shopping cart only in its local memory, App B may not know about that cart.&lt;/p&gt;

&lt;h3&gt;
  
  
  Replication
&lt;/h3&gt;

&lt;p&gt;Replication stores copies of data on multiple nodes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Write
               |
               v
          Primary Node
           /        \
          v          v
      Replica B   Replica C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replication can improve durability, read capacity, and failover. The exact guarantees depend on how writes are acknowledged and how replicas are kept in sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  Partitioning or sharding
&lt;/h3&gt;

&lt;p&gt;Partitioning divides a dataset into pieces, often by key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Users 1-1000       -&amp;gt; Shard A
Users 1001-2000    -&amp;gt; Shard B
Users 2001-3000    -&amp;gt; Shard C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sharding increases capacity by spreading data across nodes. It introduces challenges around routing, rebalancing, and operations that touch multiple shards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Message queues
&lt;/h3&gt;

&lt;p&gt;A queue decouples producers from consumers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order API -&amp;gt; Message Queue -&amp;gt; Email Worker
                         \-&amp;gt; Billing Worker
                         \-&amp;gt; Analytics Worker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The producer can enqueue work without waiting for every consumer to finish. The system must still account for retries, duplicate delivery, ordering, and poison messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consensus
&lt;/h3&gt;

&lt;p&gt;Consensus helps a group of nodes agree on a value or a sequence of values.&lt;/p&gt;

&lt;p&gt;It is useful when the system needs one agreed decision, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which node is the leader?&lt;/li&gt;
&lt;li&gt;Which configuration is active?&lt;/li&gt;
&lt;li&gt;What is the committed order of updates?&lt;/li&gt;
&lt;li&gt;Which log entries may be applied to the state machine?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Raft is a consensus algorithm designed around replicated logs.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Replication and consistency
&lt;/h2&gt;

&lt;p&gt;Replication means keeping multiple copies of data. The central design question is &lt;strong&gt;when a write is considered successful and what a reader is allowed to observe&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Synchronous replication
&lt;/h3&gt;

&lt;p&gt;A write is acknowledged only after the required replicas have confirmed it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
  |
  v
Leader
  |------ Write ------&amp;gt; Replica B
  |------ Write ------&amp;gt; Replica C
  |&amp;lt;----- Ack ---------|
  |&amp;lt;----- Ack --------------------|
  |
  v
Client receives success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual acknowledgement rule depends on the system. Waiting for more replicas can improve durability, but it may increase latency and reduce availability when replicas are unreachable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous replication
&lt;/h3&gt;

&lt;p&gt;The primary acknowledges a write before all replicas have received it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client -&amp;gt; Primary -&amp;gt; Client success
             |
             | replication continues later
             v
          Replica
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can reduce write latency, but a primary failure may cause recently acknowledged data to be missing from a replica that is promoted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strong and eventual consistency
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Strong consistency&lt;/strong&gt; is a broad phrase used for systems that provide stronger guarantees about what reads can observe. The exact guarantee should be named rather than assumed.&lt;/p&gt;

&lt;p&gt;For example, &lt;strong&gt;linearizability&lt;/strong&gt; requires each operation to appear as if it took effect at one instant between its invocation and response, while respecting real-time ordering of non-overlapping operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eventual consistency&lt;/strong&gt; means replicas can temporarily disagree, but if updates stop and communication continues under the system's assumptions, replicas eventually converge.&lt;/p&gt;

&lt;p&gt;Neither label automatically tells you every detail about transactions, durability, or failure behavior. Read the actual consistency model.&lt;/p&gt;

&lt;h3&gt;
  
  
  A concrete example
&lt;/h3&gt;

&lt;p&gt;Suppose an account has a balance of ₹1,000.&lt;/p&gt;

&lt;p&gt;A client sends a debit of ₹200. The primary updates its copy to ₹800 and acknowledges the request. An asynchronous replica still has ₹1,000.&lt;/p&gt;

&lt;p&gt;If the primary crashes and the stale replica is promoted, a read might return ₹1,000. Depending on the design, the acknowledged debit may have been lost.&lt;/p&gt;

&lt;p&gt;With consensus-backed replicated state, a write can be acknowledged only after the protocol's commit condition is met. This reduces the risk of promoting a node whose log is missing a committed entry.&lt;/p&gt;

&lt;p&gt;Consensus does not automatically make every application operation correct. The application still needs appropriate transaction logic, validation, and request retry handling.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The CAP theorem
&lt;/h2&gt;

&lt;p&gt;CAP describes a trade-off that appears when a distributed data system experiences a network partition.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency (C):&lt;/strong&gt; in the usual CAP formulation, operations behave as if there is a single up-to-date copy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability (A):&lt;/strong&gt; every request to a non-failing node receives a response, even if that response cannot include the latest write.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partition tolerance (P):&lt;/strong&gt; the system continues operating despite messages being lost or delayed between groups of nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a partition occurs, a system cannot guarantee both linearizable consistency and availability for every request. It must sometimes reject or delay operations on one side to preserve consistency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Network partition
              Node A       Node B
                 |             |
                 X  no link    X

Consistency-first:
  One side may reject writes until agreement is possible.

Availability-first:
  Both sides may accept writes, risking conflicting updates.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few important qualifications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CAP is about behavior during a partition, not a universal rule that every system is simply "CP" or "AP" at all times.&lt;/li&gt;
&lt;li&gt;Real systems make choices per operation, data type, and failure condition.&lt;/li&gt;
&lt;li&gt;A timeout does not prove a partition. It is how a client or node detects that progress is not happening quickly enough.&lt;/li&gt;
&lt;li&gt;CAP does not mean performance, latency, or durability are irrelevant. It addresses a specific consistency and availability trade-off under partition.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Raft generally chooses safety over accepting conflicting writes. A Raft group needs a majority to elect a leader and commit new entries. A minority partition cannot independently commit entries.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. What is consensus?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Consensus&lt;/strong&gt; is the problem of getting multiple nodes to agree on a value despite failures and unreliable communication.&lt;/p&gt;

&lt;p&gt;Imagine five machines must agree on the next configuration version. Each machine may have a different initial view, and some machines may crash or be unreachable.&lt;/p&gt;

&lt;p&gt;A consensus protocol aims to ensure that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Agreement:&lt;/strong&gt; nodes do not decide on conflicting values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validity:&lt;/strong&gt; a decided value must satisfy the protocol's validity rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Termination:&lt;/strong&gt; under the protocol's assumptions, nodes eventually decide.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Exact definitions differ between consensus formulations. In replicated state machines, consensus is usually applied repeatedly to establish an ordered sequence of commands.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why a simple vote is not enough
&lt;/h3&gt;

&lt;p&gt;Suppose three nodes vote on whether to write a value. If a response is delayed, one node might assume a peer has failed. If each side of a partition can decide independently, they might accept conflicting results.&lt;/p&gt;

&lt;p&gt;A consensus protocol needs explicit rules for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who may propose a value.&lt;/li&gt;
&lt;li&gt;How many nodes must acknowledge it.&lt;/li&gt;
&lt;li&gt;How to handle competing proposals.&lt;/li&gt;
&lt;li&gt;What happens after a leader or voter crashes.&lt;/li&gt;
&lt;li&gt;How a newly elected leader learns which values were already decided.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Raft combines leader election with replicated log rules to answer these questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Majority quorum
&lt;/h3&gt;

&lt;p&gt;For a cluster of (N) voting nodes, a majority quorum is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Q = \left\lfloor \frac{N}{2} \right\rfloor + 1&lt;br&gt;
]&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Voting nodes&lt;/th&gt;
&lt;th&gt;Majority required&lt;/th&gt;
&lt;th&gt;Nodes that can fail while a majority remains&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A majority is important because any two majorities in the same fixed voting configuration overlap in at least one node.&lt;/p&gt;

&lt;p&gt;For five nodes, any majority contains three nodes. Two groups of three selected from the same five nodes must share at least one member.&lt;/p&gt;

&lt;p&gt;This overlap helps preserve safety, but it is not the whole proof. Raft also relies on terms, voting restrictions, and log freshness rules to ensure a newly elected leader cannot overwrite committed history.&lt;/p&gt;

&lt;p&gt;For a fixed Raft group, losing the majority means losing the ability to commit new entries. The minority may still run, but it cannot safely act as an independent leader.&lt;/p&gt;


&lt;h2&gt;
  
  
  7. Why Raft?
&lt;/h2&gt;

&lt;p&gt;Raft is a consensus algorithm introduced as an alternative to Paxos with an emphasis on understandability. It is commonly used to build replicated state machines.&lt;/p&gt;

&lt;p&gt;The core idea is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Elect one leader.&lt;/li&gt;
&lt;li&gt;Send client commands to that leader.&lt;/li&gt;
&lt;li&gt;Replicate the leader's log entries to followers.&lt;/li&gt;
&lt;li&gt;Commit entries when the protocol's quorum and log rules permit.&lt;/li&gt;
&lt;li&gt;Apply committed entries to each node's state machine in order.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Client write
                      |
                      v
                +-----------+
                |  Leader   |
                +-----------+
                 /         \
                v           v
          +-----------+ +-----------+
          | Follower  | | Follower  |
          +-----------+ +-----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The leader coordinates log replication. Followers do not independently accept a competing log as committed.&lt;/p&gt;
&lt;h3&gt;
  
  
  What Raft does not do
&lt;/h3&gt;

&lt;p&gt;Raft is not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A load balancer.&lt;/li&gt;
&lt;li&gt;A database query engine.&lt;/li&gt;
&lt;li&gt;A replacement for networking.&lt;/li&gt;
&lt;li&gt;A guarantee that every request always succeeds.&lt;/li&gt;
&lt;li&gt;A general-purpose distributed transaction protocol across unrelated services.&lt;/li&gt;
&lt;li&gt;A way to make a cluster tolerate unlimited failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It provides a foundation for agreement on replicated log entries. The application built on top of it defines what those entries mean.&lt;/p&gt;
&lt;h3&gt;
  
  
  The replicated state machine model
&lt;/h3&gt;

&lt;p&gt;A state machine takes an ordered sequence of commands and produces state transitions.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Initial state: balance = 1000

Command 1: Deposit(500)
State:     balance = 1500

Command 2: Withdraw(200)
State:     balance = 1300

Command 3: Deposit(100)
State:     balance = 1400
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If every node starts from the same state and applies the same deterministic commands in the same order, every node reaches the same result.&lt;/p&gt;

&lt;p&gt;This is the key idea behind a replicated state machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Replicated log
          [C1] [C2] [C3] [C4]
             |    |    |    |
             v    v    v    v
        +-----------------------+
        | Apply commands in     |
        | the same order        |
        +-----------------------+
             |             |
             v             v
         State A        State B

         Same log + same deterministic
         transitions = same logical state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a command depends on nondeterministic local behavior, such as reading the current clock independently on each node, nodes may diverge. Such values should be captured in the replicated command or otherwise handled consistently.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Raft cluster architecture
&lt;/h2&gt;

&lt;p&gt;Raft describes three main node roles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leader
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;Accepts client commands.&lt;/li&gt;
&lt;li&gt;Appends commands to its local log.&lt;/li&gt;
&lt;li&gt;Replicates log entries to followers.&lt;/li&gt;
&lt;li&gt;Tracks replication progress.&lt;/li&gt;
&lt;li&gt;Determines when entries can be committed.&lt;/li&gt;
&lt;li&gt;Sends heartbeats to maintain leadership.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There should be at most one leader whose authority is accepted for a given term. During elections or partitions, nodes may temporarily have different beliefs about leadership, but Raft's safety rules prevent conflicting leaders from committing conflicting entries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Follower
&lt;/h3&gt;

&lt;p&gt;A follower:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Responds to leader heartbeats.&lt;/li&gt;
&lt;li&gt;Accepts log entries from the leader.&lt;/li&gt;
&lt;li&gt;Votes in elections when eligible.&lt;/li&gt;
&lt;li&gt;Starts an election if it does not hear from a valid leader within its election timeout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of the time, a follower is waiting for messages or persisting replicated state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Candidate
&lt;/h3&gt;

&lt;p&gt;A candidate is a node trying to become leader. It starts an election, increments its term, votes for itself, and requests votes from other nodes.&lt;/p&gt;

&lt;p&gt;If it receives votes from a majority, it becomes leader. If it learns of a newer term, it steps down. If no candidate wins, another election may begin after a timeout.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node state
&lt;/h3&gt;

&lt;p&gt;A Raft implementation stores persistent and volatile state. The exact internal implementation varies, but the classic Raft description includes the following.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Persistent state&lt;/strong&gt;, which must survive a crash:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;currentTerm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Highest term the node has observed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;votedFor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Candidate that received this node's vote in the current term, if any&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;log[]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replicated log entries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Volatile state:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;commitIndex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Highest log index known to be committed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lastApplied&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Highest log index applied to the state machine&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The leader also tracks replication progress for each follower, commonly with fields like &lt;code&gt;nextIndex[]&lt;/code&gt; and &lt;code&gt;matchIndex[]&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nextIndex[follower]&lt;/code&gt; is the next log index the leader plans to send to that follower.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;matchIndex[follower]&lt;/code&gt; is the highest index the leader knows that follower has replicated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These indexes are not interchangeable. &lt;code&gt;nextIndex&lt;/code&gt; is a replication guess that can move backward after a rejection. &lt;code&gt;matchIndex&lt;/code&gt; records confirmed replication progress and is used when calculating commitment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terms
&lt;/h3&gt;

&lt;p&gt;Raft divides time into &lt;strong&gt;terms&lt;/strong&gt;, numbered with increasing integers. A term begins with an election and may contain a leader.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Term 1             Term 2             Term 3
--------           --------           --------
Leader A           Leader C           Leader B
   |                   |                  |
   v                   v                  v
 log entries        log entries       log entries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A term can end without a successful leader being elected. Several candidates may time out and start elections in successive terms.&lt;/p&gt;

&lt;p&gt;Terms act like a logical clock for leadership changes. If a node receives a message with a term higher than its current term, it updates its term and returns to follower state.&lt;/p&gt;

&lt;h3&gt;
  
  
  The three main RPCs
&lt;/h3&gt;

&lt;p&gt;The Raft paper describes three core remote procedure calls:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;RPC&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RequestVote&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ask peers to vote during an election&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AppendEntries&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replicate log entries and send heartbeats&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;InstallSnapshot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transfer a snapshot to a follower that needs compacted history&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;An empty &lt;code&gt;AppendEntries&lt;/code&gt; request can act as a heartbeat. Implementations may use additional internal messages, but these are the central Raft RPCs.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Leader election
&lt;/h2&gt;

&lt;p&gt;Leader election happens when a follower stops receiving valid heartbeats for long enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Election flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Follower timeout
      |
      v
Increment currentTerm
      |
      v
Become Candidate
      |
      v
Vote for self
      |
      v
Send RequestVote to peers
      |
      v
Receive responses
      |
      +-------------------------------+
      |                               |
      v                               v
Majority votes                    Higher term seen
      |                               |
      v                               v
Become Leader                   Become Follower
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the candidate receives votes from a majority, it becomes leader for that term.&lt;/p&gt;

&lt;p&gt;If it discovers a higher term, it steps down. If it does not win, the election may time out and restart.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is in a RequestVote?
&lt;/h3&gt;

&lt;p&gt;Conceptually, a vote request includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The candidate's current term.&lt;/li&gt;
&lt;li&gt;The candidate's identity.&lt;/li&gt;
&lt;li&gt;The index of its last log entry.&lt;/li&gt;
&lt;li&gt;The term of its last log entry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The receiving node grants its vote only if the request satisfies the protocol rules. Important checks include whether the candidate's term is current enough, whether the voter has already voted for someone else in that term, and whether the candidate's log is at least as up to date as the voter's log.&lt;/p&gt;

&lt;p&gt;The last check is essential. A candidate cannot win merely by collecting votes if its log is too stale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why random election timeouts?
&lt;/h3&gt;

&lt;p&gt;If every follower starts an election at exactly the same time, votes can split across candidates. No candidate may receive a majority.&lt;/p&gt;

&lt;p&gt;Randomized election timeouts reduce the chance that several nodes start elections together.&lt;/p&gt;

&lt;p&gt;For example, a system might configure election timeouts in a range such as 300 to 600 milliseconds. Those numbers are illustrative, not universal recommendations. Real values depend on network latency, disk persistence, scheduling pauses, and the implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node A timeout: 420 ms
Node B timeout: 570 ms
Node C timeout: 360 ms

Node C times out first and starts an election.
If it gets a majority, the other nodes hear from the new leader
and do not need to start competing elections.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Heartbeats
&lt;/h3&gt;

&lt;p&gt;A leader periodically sends empty &lt;code&gt;AppendEntries&lt;/code&gt; messages to followers.&lt;/p&gt;

&lt;p&gt;These heartbeats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tell followers the leader is still active.&lt;/li&gt;
&lt;li&gt;Carry the leader's current term.&lt;/li&gt;
&lt;li&gt;Help followers reset their election timers.&lt;/li&gt;
&lt;li&gt;Can communicate the leader's commit index.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Heartbeats are not proof that every follower has replicated every entry. They establish contact and help maintain leadership. Log replication still needs to succeed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why election timeouts are not failure detectors
&lt;/h3&gt;

&lt;p&gt;If a follower times out, it suspects the leader may be unavailable. The leader could actually be healthy but delayed by CPU starvation, a long pause, a network problem, or slow disk I/O.&lt;/p&gt;

&lt;p&gt;Raft can tolerate this uncertainty because safety does not depend on the timeout being perfect. Timeouts affect how quickly a new leader is elected and how often elections happen. Terms, voting rules, and log restrictions protect safety.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Log replication
&lt;/h2&gt;

&lt;p&gt;Once elected, the leader handles client commands by appending them to its log and replicating them to followers.&lt;/p&gt;

&lt;p&gt;Each log entry contains a command and the term in which that entry was created. Entries also have an index, which defines their position in the log.&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Index&lt;/th&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SetMode("safe")&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CreateUser(42)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Deposit(500)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Withdraw(100)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The same index and term information helps Raft check whether two logs agree.&lt;/p&gt;

&lt;h3&gt;
  
  
  The normal write path
&lt;/h3&gt;

&lt;p&gt;Suppose a client sends &lt;code&gt;Deposit(500)&lt;/code&gt; to the leader.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client          Leader          Follower B       Follower C
  |                |                 |                 |
  | Deposit(500)   |                 |                 |
  |---------------&amp;gt;|                 |                 |
  |                | Append locally  |                 |
  |                |------ AppendEntries -------------&amp;gt;|
  |                |-----------------&amp;gt;|                 |
  |                |                 | Persist entry    |
  |                |&amp;lt;----- success --|                 |
  |                |&amp;lt;---------------------- success ---|
  |                |                 |                 |
  |                | Majority has replicated entry     |
  |                | Mark entry committed, if rules allow
  |&amp;lt;---------------|                 |                 |
  | Success        |                 |                 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diagram shows the main idea. A production implementation must handle persistence ordering, retries, rejections, terms, and commit rules correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step by step
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;The leader receives the command.&lt;/li&gt;
&lt;li&gt;The leader appends it to its local log.&lt;/li&gt;
&lt;li&gt;The leader sends &lt;code&gt;AppendEntries&lt;/code&gt; requests to followers.&lt;/li&gt;
&lt;li&gt;Followers check that the incoming entries match the preceding log position and term.&lt;/li&gt;
&lt;li&gt;Followers append missing entries and persist the required state.&lt;/li&gt;
&lt;li&gt;The leader tracks successful replication.&lt;/li&gt;
&lt;li&gt;Once the relevant commitment rule is satisfied, the entry becomes committed.&lt;/li&gt;
&lt;li&gt;The leader applies committed commands to its state machine and informs followers of the commit index.&lt;/li&gt;
&lt;li&gt;The client receives a response according to the implementation's acknowledgement contract.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A leader does not need every node to respond before making progress. It needs the required quorum.&lt;/p&gt;

&lt;h3&gt;
  
  
  AppendEntries consistency check
&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;AppendEntries&lt;/code&gt; request includes the index and term of the entry immediately preceding the new entries. The follower checks whether its log contains an entry at that index with the same term.&lt;/p&gt;

&lt;p&gt;If it does not, the follower rejects the request. The leader adjusts its replication position and retries with an earlier prefix until the logs match, then sends the missing entries.&lt;/p&gt;

&lt;p&gt;This is how a new leader repairs divergent, uncommitted log suffixes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logs can differ temporarily
&lt;/h3&gt;

&lt;p&gt;A follower may be behind the leader. It may also contain entries from an older leader that were never committed.&lt;/p&gt;

&lt;p&gt;Raft does not require every log to match at every moment. It requires committed history to be preserved and provides a mechanism for bringing follower logs into agreement.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Terms, log matching, and safety
&lt;/h2&gt;

&lt;p&gt;The most important Raft properties are not just about copying entries. They are about ensuring that copied entries represent one safe history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log index and term
&lt;/h3&gt;

&lt;p&gt;An entry has an index and a term.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;index&lt;/strong&gt; identifies its position in the log.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;term&lt;/strong&gt; identifies the leadership term in which it was created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two entries with the same index and term must contain the same command under Raft's log-matching property. If two logs contain an entry with the same index and term, all preceding entries in those logs must also match.&lt;/p&gt;

&lt;p&gt;This allows a leader to establish a matching prefix before repairing a follower's log.&lt;/p&gt;

&lt;h3&gt;
  
  
  Election restriction
&lt;/h3&gt;

&lt;p&gt;A candidate's log must be at least as up to date as the log of a node granting it a vote.&lt;/p&gt;

&lt;p&gt;The comparison uses the term of the last log entry first. A log whose last entry has a higher term is considered more up to date. If the last terms are equal, the log with the greater last index is more up to date.&lt;/p&gt;

&lt;p&gt;This restriction helps ensure a leader elected by a majority contains the history required to preserve committed entries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why a majority alone is not the full explanation
&lt;/h3&gt;

&lt;p&gt;It is tempting to say, "A majority replicated the entry, so it is safe forever." The full Raft reasoning is more specific.&lt;/p&gt;

&lt;p&gt;A majority matters because future majorities overlap with the earlier majority. But the node in that overlap must also follow the voting and log-freshness rules. Those rules help ensure a future leader has the necessary committed history.&lt;/p&gt;

&lt;p&gt;The protocol's safety argument depends on the combination of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Majority quorums.&lt;/li&gt;
&lt;li&gt;Persistent terms and votes.&lt;/li&gt;
&lt;li&gt;The log-matching property.&lt;/li&gt;
&lt;li&gt;Election restrictions.&lt;/li&gt;
&lt;li&gt;The rule for advancing the commit index.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Important Raft safety properties
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Practical meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Election Safety&lt;/td&gt;
&lt;td&gt;At most one leader can be elected in a given term&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Leader Append-Only&lt;/td&gt;
&lt;td&gt;A leader does not overwrite or delete entries from its own log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Log Matching&lt;/td&gt;
&lt;td&gt;Matching index and term imply matching entries and prefixes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Leader Completeness&lt;/td&gt;
&lt;td&gt;A leader elected in a later term contains entries committed in earlier terms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State Machine Safety&lt;/td&gt;
&lt;td&gt;No two nodes apply different commands at the same log index&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These properties work together. A correct implementation must preserve the required state and ordering rules, including across crashes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Persistent state and crashes
&lt;/h3&gt;

&lt;p&gt;Suppose a node grants a vote, then crashes and restarts. If it forgets that vote, it could vote for another candidate in the same term. That could break election safety.&lt;/p&gt;

&lt;p&gt;This is why Raft's persistent state must be stored reliably before the node responds in ways that depend on it. Details such as write-ahead logging, fsync behavior, and storage guarantees are implementation concerns, but they are not optional details for a correct implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Committing entries
&lt;/h2&gt;

&lt;p&gt;An entry is &lt;strong&gt;committed&lt;/strong&gt; when Raft's commitment rules establish that it is part of the agreed history. Committed entries are safe to apply to the state machine.&lt;/p&gt;

&lt;p&gt;The leader tracks which entries have been replicated on a majority. For each follower, &lt;code&gt;matchIndex&lt;/code&gt; records the highest entry index known to be replicated there.&lt;/p&gt;

&lt;p&gt;For a fixed configuration of five voters, an entry replicated on three voters has majority replication. However, the leader's commit rule has an important term restriction.&lt;/p&gt;

&lt;h3&gt;
  
  
  The current-term rule
&lt;/h3&gt;

&lt;p&gt;In the standard Raft algorithm, a leader advances &lt;code&gt;commitIndex&lt;/code&gt; directly based on majority replication only when the candidate entry is from the leader's &lt;strong&gt;current term&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why? An entry from an earlier term may have been replicated on a majority at some point but still be vulnerable under the protocol's rules if treated as committed only by counting replicas. Committing a current-term entry establishes the required history, and earlier entries in the matching prefix become committed along with it.&lt;/p&gt;

&lt;p&gt;This is a subtle but important distinction. Do not reduce Raft's commit rule to "any entry on a majority is always committed."&lt;/p&gt;

&lt;h3&gt;
  
  
  Example with five nodes
&lt;/h3&gt;

&lt;p&gt;Suppose the cluster has five voters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Leader A
Follower B
Follower C
Follower D
Follower E
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A majority is three nodes.&lt;/p&gt;

&lt;p&gt;If A, B, and C have replicated a current-term entry and the required protocol conditions are met, the leader can commit it. D and E can catch up later.&lt;/p&gt;

&lt;p&gt;If A can only communicate with B, it has two nodes and cannot commit new entries. It must not treat its own local log as a committed decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Committed versus applied
&lt;/h3&gt;

&lt;p&gt;These terms mean different things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Replicated:&lt;/strong&gt; an entry exists in more than one node's log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Committed:&lt;/strong&gt; the protocol has established that the entry is part of the agreed history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Applied:&lt;/strong&gt; the node has executed the command against its state machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An entry can be committed but not yet applied if the node is still processing earlier entries or recovering after a restart.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Log entries:  [1] [2] [3] [4] [5]
                         ^
                    commitIndex

Applied entries: [1] [2] [3]
                         ^
                    lastApplied
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, entry 4 may be committed but not yet applied. The state machine must apply entries in order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why clients should care
&lt;/h3&gt;

&lt;p&gt;If a server returns success before the operation is safely committed, a leader failure may cause the client to believe a write succeeded even though it is not part of the durable agreed history.&lt;/p&gt;

&lt;p&gt;The API's success response should have a clearly defined meaning. In a consensus-backed service, a common contract is to return success after the command is committed and applied, or after the implementation's documented equivalent point.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. Client requests and linearizability
&lt;/h2&gt;

&lt;p&gt;Clients usually send writes to the leader. A follower may redirect the client to the leader or proxy the request, depending on the implementation.&lt;/p&gt;

&lt;p&gt;A basic write path looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
  |
  v
Known endpoint
  |
  +---- follower? ----&amp;gt; redirect or proxy
  |
  v
Leader
  |
  v
Replicate and commit
  |
  v
Apply command
  |
  v
Return result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What if the leader changes during a request?
&lt;/h3&gt;

&lt;p&gt;Imagine a client sends a write to Leader A. A loses contact with the majority. Before the client receives a response, a new leader is elected.&lt;/p&gt;

&lt;p&gt;The client may time out and retry. The original operation might have committed, or it might not have. A timeout alone does not resolve the uncertainty.&lt;/p&gt;

&lt;p&gt;Applications can address this with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unique operation IDs.&lt;/li&gt;
&lt;li&gt;Idempotency keys.&lt;/li&gt;
&lt;li&gt;A replicated record of completed requests.&lt;/li&gt;
&lt;li&gt;Explicit status lookup APIs.&lt;/li&gt;
&lt;li&gt;Carefully defined retry behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, instead of sending &lt;code&gt;Deposit(500)&lt;/code&gt; as an unidentifiable command every time, a client could send &lt;code&gt;Deposit(request_id="r-123", amount=500)&lt;/code&gt;. The state machine can remember the request ID and return the prior result if the same operation is retried.&lt;/p&gt;

&lt;p&gt;The deduplication record must be stored and applied consistently with the operation. Keeping it only in local memory would not survive failover.&lt;/p&gt;

&lt;h3&gt;
  
  
  Linearizability
&lt;/h3&gt;

&lt;p&gt;Linearizability is a consistency guarantee that makes each operation appear to take effect at one instant between its start and completion, while respecting the real-time order of operations that do not overlap.&lt;/p&gt;

&lt;p&gt;A replicated state machine can provide linearizable writes when the complete implementation follows the necessary protocol and client-serving rules.&lt;/p&gt;

&lt;p&gt;Reads need care too. A leader that has been isolated from a majority might not know it has lost leadership. Serving a read from stale local state could violate linearizability.&lt;/p&gt;

&lt;p&gt;Implementations use techniques such as quorum-confirmed reads or a correctly implemented &lt;code&gt;ReadIndex&lt;/code&gt; mechanism. Lease-based reads are another option, but they require assumptions about timing and clock behavior to be satisfied.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not assume that every read served by a node calling itself leader is automatically linearizable.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  14. What happens when nodes fail?
&lt;/h2&gt;

&lt;p&gt;A distributed system should be designed around failure scenarios, not only the happy path.&lt;/p&gt;

&lt;h3&gt;
  
  
  One follower crashes in a three-node cluster
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A: Leader, healthy
B: Follower, crashed
C: Follower, healthy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A and C are a majority of two out of three. The cluster can continue committing entries if they can communicate and the other required conditions hold.&lt;/p&gt;

&lt;p&gt;B can restart later and catch up from the leader.&lt;/p&gt;

&lt;h3&gt;
  
  
  The leader crashes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before failure:

       A (Leader)
       /        \
      B          C

A crashes
    X

B and C stop hearing heartbeats.
One times out and starts an election.
A majority elects a new leader.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cluster may pause while a new leader is elected. Requests during that interval can time out or fail. Raft aims to preserve safety while allowing progress once a majority can communicate.&lt;/p&gt;

&lt;h3&gt;
  
  
  A minority partition
&lt;/h3&gt;

&lt;p&gt;For five voters, imagine a partition splits the cluster into groups of three and two.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition 1                  Partition 2
+------------------+         +------------------+
| A  B  C          |    X    | D  E             |
| majority: 3      |         | minority: 2      |
+------------------+         +------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The three-node side can elect a leader and commit new entries. The two-node side cannot commit new entries because it cannot reach a majority.&lt;/p&gt;

&lt;p&gt;If the minority still believes an old leader is active, it may accept a connection or hold uncommitted local state depending on the implementation, but it cannot safely commit new entries independently.&lt;/p&gt;

&lt;p&gt;When the partition heals, the current leader reconciles followers' uncommitted log suffixes.&lt;/p&gt;

&lt;h3&gt;
  
  
  All nodes lose their majority
&lt;/h3&gt;

&lt;p&gt;If only one node in a three-node cluster is reachable, it cannot commit new entries. It may have a local log and may still be running, but it cannot establish quorum.&lt;/p&gt;

&lt;p&gt;This is intentional. Rejecting or delaying writes is preferable to accepting conflicting histories.&lt;/p&gt;

&lt;h3&gt;
  
  
  A slow disk
&lt;/h3&gt;

&lt;p&gt;A node can be alive at the process level but unable to persist entries quickly. This may delay acknowledgements, cause timeouts, and trigger elections.&lt;/p&gt;

&lt;p&gt;For a consensus implementation, disk latency is not merely a storage performance concern. Persistent state and log entries are part of the correctness protocol.&lt;/p&gt;

&lt;h3&gt;
  
  
  Restart and recovery
&lt;/h3&gt;

&lt;p&gt;After restart, a node recovers persistent state, including its term, vote, and log. It learns the current leader and reconciles its log.&lt;/p&gt;

&lt;p&gt;A node must not treat uncommitted local entries as committed simply because they survived on disk. Commitment depends on the protocol's rules and information from the current cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failure tolerance by cluster size
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Voters&lt;/th&gt;
&lt;th&gt;Majority&lt;/th&gt;
&lt;th&gt;Maximum unavailable voters while retaining a majority&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;More voters increase failure tolerance but also increase the number of machines involved in elections and the potential communication overhead. In many deployments, three or five voters are common choices. The right number depends on failure domains, latency, operational requirements, and implementation guidance.&lt;/p&gt;

&lt;p&gt;A five-node cluster in one rack does not protect against losing the entire rack. Place replicas across independent failure domains when the infrastructure and latency requirements allow it.&lt;/p&gt;




&lt;h2&gt;
  
  
  15. Snapshots and log compaction
&lt;/h2&gt;

&lt;p&gt;A replicated log grows as commands are added. Keeping every command forever makes storage usage grow without bound.&lt;/p&gt;

&lt;p&gt;Raft implementations can use &lt;strong&gt;snapshots&lt;/strong&gt; to compact old log entries.&lt;/p&gt;

&lt;p&gt;A snapshot captures the state machine state through a particular log index and term. Once the snapshot is safely stored, entries covered by it can be discarded according to the implementation's rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before snapshot:

Log: [1] [2] [3] [4] [5] [6] [7] [8] [9]

Snapshot covers entries through index 6.

After compaction:

Snapshot at index 6
Log:                  [7] [8] [9]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The snapshot must include enough metadata to establish the last included index and term. That allows Raft to continue matching logs after older entries have been removed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if a follower is far behind?
&lt;/h3&gt;

&lt;p&gt;If a follower's missing entries have already been compacted from the leader's log, the leader cannot repair it by sending those old entries one by one. It may need to send a snapshot using &lt;code&gt;InstallSnapshot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The follower installs the snapshot according to the protocol and then continues receiving log entries after the snapshot's index.&lt;/p&gt;

&lt;h3&gt;
  
  
  Snapshot considerations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Snapshot data must correspond to a consistent state machine position.&lt;/li&gt;
&lt;li&gt;The last included index and term must be retained.&lt;/li&gt;
&lt;li&gt;Installation should not expose partially written state.&lt;/li&gt;
&lt;li&gt;The implementation must handle crashes during snapshot creation or installation.&lt;/li&gt;
&lt;li&gt;Snapshot size and frequency affect disk usage, recovery time, and network traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Snapshots are a storage and recovery mechanism. They do not replace the consensus protocol.&lt;/p&gt;




&lt;h2&gt;
  
  
  16. Membership changes
&lt;/h2&gt;

&lt;p&gt;What if a three-node cluster needs to become a five-node cluster? Changing membership is not just a matter of adding two machines to a list.&lt;/p&gt;

&lt;p&gt;If old and new configurations used unrelated quorum rules at the same time, different groups could potentially make conflicting decisions.&lt;/p&gt;

&lt;p&gt;Raft handles membership changes through a protocol designed to preserve quorum safety during transitions. The original Raft approach uses &lt;strong&gt;joint consensus&lt;/strong&gt;, where the system temporarily requires agreement under both the old and new configurations.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Old configuration: {A, B, C}

Transition:
  Joint configuration includes old and new membership rules.

New configuration: {A, B, C, D, E}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During the joint phase, decisions require the necessary majorities of both configurations. Once the transition is committed, the new configuration becomes active.&lt;/p&gt;

&lt;p&gt;Implementations may use different, carefully designed membership-change procedures. Follow the specific implementation's documentation rather than manually changing voter lists while the cluster is running.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why adding a node is not enough
&lt;/h3&gt;

&lt;p&gt;A new node usually needs to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Be provisioned with the correct identity and configuration.&lt;/li&gt;
&lt;li&gt;Join through the supported membership-change mechanism.&lt;/li&gt;
&lt;li&gt;Receive the log or a snapshot.&lt;/li&gt;
&lt;li&gt;Catch up with the cluster.&lt;/li&gt;
&lt;li&gt;Become a voter only when the protocol permits it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A node that is present on the network is not automatically a safe voting member.&lt;/p&gt;




&lt;h2&gt;
  
  
  17. A worked example
&lt;/h2&gt;

&lt;p&gt;Let's walk through a three-node cluster that stores a simple account balance.&lt;/p&gt;

&lt;p&gt;Initial state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Node A: Leader
Node B: Follower
Node C: Follower

Balance = 1000
Commit index = 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three nodes have applied log entries through index 4.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: A client requests a deposit
&lt;/h3&gt;

&lt;p&gt;The client sends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"requestId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deposit-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deposit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The leader appends a new log entry:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Index&lt;/th&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Deposit(500)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Appended on A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The entry is not committed merely because A wrote it locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: The leader replicates the entry
&lt;/h3&gt;

&lt;p&gt;A sends &lt;code&gt;AppendEntries&lt;/code&gt; to B and C.&lt;/p&gt;

&lt;p&gt;Suppose B acknowledges after persisting the entry. The entry now exists on A and B.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A: [1] [2] [3] [4] [5]
B: [1] [2] [3] [4] [5]
C: [1] [2] [3] [4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two of three voters have the entry. If it is from the current term and the required Raft conditions hold, A can advance the commit index to 5.&lt;/p&gt;

&lt;p&gt;C can be temporarily behind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: The entry is committed and applied
&lt;/h3&gt;

&lt;p&gt;A applies &lt;code&gt;Deposit(500)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Balance: 1000 + 500 = 1500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A can return the result according to its client acknowledgement contract.&lt;/p&gt;

&lt;p&gt;Later, A informs C of the updated commit index, and C applies the same command after replicating it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A: Balance = 1500
B: Balance = 1500
C: Balance = 1500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All nodes apply the same committed command in the same order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: The leader fails
&lt;/h3&gt;

&lt;p&gt;A crashes before C catches up.&lt;/p&gt;

&lt;p&gt;B and C remain. If they can communicate, they form a majority and can elect a new leader. B already has the committed entry at index 5, so the election restriction helps prevent a candidate missing committed history from winning.&lt;/p&gt;

&lt;p&gt;After the new leader is established, the cluster continues from the agreed history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: The client retries after a timeout
&lt;/h3&gt;

&lt;p&gt;Suppose the client never received the success response from A. It cannot know whether the deposit was committed.&lt;/p&gt;

&lt;p&gt;It retries with &lt;code&gt;requestId: "deposit-001"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the state machine records request IDs with their results, the new leader can recognize the retry and return the previous result instead of applying the deposit twice. Without a deduplication design, retrying a non-idempotent command can double the balance.&lt;/p&gt;

&lt;p&gt;This is an application-level concern built on top of Raft. Consensus orders commands, but it does not automatically know that two requests from a client represent the same intended operation.&lt;/p&gt;




&lt;h2&gt;
  
  
  18. Raft versus other approaches
&lt;/h2&gt;

&lt;p&gt;Raft is not the only way to replicate data or coordinate machines. Different tools solve different problems.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Main idea&lt;/th&gt;
&lt;th&gt;Useful when&lt;/th&gt;
&lt;th&gt;Important limitation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary-replica replication&lt;/td&gt;
&lt;td&gt;One primary accepts writes and sends updates to replicas&lt;/td&gt;
&lt;td&gt;Read scaling and straightforward failover&lt;/td&gt;
&lt;td&gt;Guarantees depend on acknowledgement and failover policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raft&lt;/td&gt;
&lt;td&gt;Leader replicates a log using majority-based consensus&lt;/td&gt;
&lt;td&gt;Strongly coordinated replicated state&lt;/td&gt;
&lt;td&gt;Cannot commit without a quorum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paxos family&lt;/td&gt;
&lt;td&gt;Consensus based on proposals, promises, and acceptance&lt;/td&gt;
&lt;td&gt;Building fault-tolerant agreement protocols&lt;/td&gt;
&lt;td&gt;Variants and implementations can be difficult to reason about&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gossip&lt;/td&gt;
&lt;td&gt;Nodes spread information through repeated peer exchanges&lt;/td&gt;
&lt;td&gt;Membership, failure suspicion, and eventually convergent metadata&lt;/td&gt;
&lt;td&gt;Does not by itself provide a single committed log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two-phase commit&lt;/td&gt;
&lt;td&gt;Coordinator asks participants to prepare and then commit or abort&lt;/td&gt;
&lt;td&gt;Coordinating a transaction across participants&lt;/td&gt;
&lt;td&gt;Can block under coordinator failures without additional mechanisms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CRDTs&lt;/td&gt;
&lt;td&gt;Data types merge concurrent updates using defined rules&lt;/td&gt;
&lt;td&gt;Some multi-writer, eventually consistent data&lt;/td&gt;
&lt;td&gt;Not suitable for every invariant or transaction&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These approaches are not all direct replacements for one another. For example, Raft consensus and two-phase commit solve different problems. A system can use consensus to maintain metadata and still need a transaction protocol for coordinating separate resources.&lt;/p&gt;

&lt;h3&gt;
  
  
  Raft and Paxos
&lt;/h3&gt;

&lt;p&gt;Both are families of consensus algorithms. Raft's presentation centers on a leader and a replicated log, making its operation easier for many engineers to follow. Paxos has several variants and is foundational to distributed consensus research and systems.&lt;/p&gt;

&lt;p&gt;It is not accurate to say that Raft is universally faster or safer than Paxos. Performance depends on implementation, workload, persistence, network topology, batching, and configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Raft and gossip
&lt;/h3&gt;

&lt;p&gt;Gossip is useful for spreading membership and health information. Nodes exchange observations with peers, and information gradually propagates.&lt;/p&gt;

&lt;p&gt;But gossip alone does not guarantee that a group has committed one value at one log index. Systems may use gossip for discovery or monitoring while relying on consensus for authoritative decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Raft and distributed transactions
&lt;/h3&gt;

&lt;p&gt;Raft can replicate the state of one state machine. It does not automatically make an operation spanning several independent Raft groups atomic.&lt;/p&gt;

&lt;p&gt;For example, transferring money between accounts that live in different shards may require a separate transaction design. Consensus within each shard does not, by itself, guarantee that both sides of the transfer commit together.&lt;/p&gt;




&lt;h2&gt;
  
  
  19. Where Raft is used
&lt;/h2&gt;

&lt;p&gt;Raft is useful when a service needs a reliable, agreed sequence of changes.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Cluster configuration and membership metadata.&lt;/li&gt;
&lt;li&gt;Distributed key-value stores.&lt;/li&gt;
&lt;li&gt;Coordination services.&lt;/li&gt;
&lt;li&gt;Replicated metadata for storage systems.&lt;/li&gt;
&lt;li&gt;Leader election and replicated control-plane state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some well-known systems and projects use Raft or Raft-derived designs, including etcd and Consul. Their complete behavior includes additional components, APIs, storage layers, and operational choices, so understanding Raft is a foundation rather than a complete guide to operating those products.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Kubernetes uses etcd
&lt;/h3&gt;

&lt;p&gt;Kubernetes stores cluster state in etcd. That state includes information such as Kubernetes objects and configuration used by the control plane.&lt;/p&gt;

&lt;p&gt;etcd uses the Raft consensus algorithm to replicate its data among members. This helps the cluster maintain a consistent view of stored state when a member fails, as long as the remaining members can form a quorum.&lt;/p&gt;

&lt;p&gt;A simplified view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl / API clients
         |
         v
  Kubernetes API Server
         |
         v
       etcd
   +------+------+ 
   |      |      |
   v      v      v
 Member Member Member
   A      B      C

   Raft replicates the log
   and coordinates commitment.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Kubernetes worker node does not normally run its own etcd member just because it is a worker. In a typical self-managed control plane, etcd members run on designated control-plane or dedicated machines according to the cluster design.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this matters for platform engineering
&lt;/h3&gt;

&lt;p&gt;When etcd loses quorum, the Kubernetes API may be unable to persist new state changes. Existing workloads might continue running for a while, but operations that require updating cluster state can fail.&lt;/p&gt;

&lt;p&gt;This is a useful operational distinction: a cluster's workloads, control plane, and state store are related, but they are not the same component.&lt;/p&gt;




&lt;h2&gt;
  
  
  20. Observability and debugging
&lt;/h2&gt;

&lt;p&gt;Consensus protocols are easier to operate when you can see what the nodes are doing. A cluster that appears "up" at the process level may still be unable to make progress.&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful signals
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;What it can reveal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Leader changes&lt;/td&gt;
&lt;td&gt;Unstable elections or node/network problems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Election count&lt;/td&gt;
&lt;td&gt;Repeated timeouts and leadership instability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request latency&lt;/td&gt;
&lt;td&gt;Slow network, disk, queueing, or overloaded nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit latency&lt;/td&gt;
&lt;td&gt;Time between proposal and commitment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replication lag&lt;/td&gt;
&lt;td&gt;Followers falling behind the leader&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk latency&lt;/td&gt;
&lt;td&gt;Slow persistence affecting progress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WAL size&lt;/td&gt;
&lt;td&gt;Growth in the write-ahead log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snapshot duration&lt;/td&gt;
&lt;td&gt;Cost of compaction and recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quorum availability&lt;/td&gt;
&lt;td&gt;Whether enough voting members can communicate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Metric names vary by implementation. Use the official metrics documentation for the exact service you are operating.&lt;/p&gt;

&lt;h3&gt;
  
  
  Symptoms and possible causes
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Possible causes to investigate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Repeated leader changes&lt;/td&gt;
&lt;td&gt;Election timeout too low for actual latency, packet loss, CPU pauses, slow disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Writes time out&lt;/td&gt;
&lt;td&gt;No quorum, overloaded leader, slow follower acknowledgements, disk bottleneck&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One follower falls behind&lt;/td&gt;
&lt;td&gt;Network issue, slow storage, repeated rejection while catching up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restart takes a long time&lt;/td&gt;
&lt;td&gt;Large log, snapshot work, slow storage, recovery overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High request latency&lt;/td&gt;
&lt;td&gt;Batching behavior, network round trips, fsync latency, queueing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are starting points for investigation, not definitive diagnoses.&lt;/p&gt;

&lt;h3&gt;
  
  
  A practical debugging order
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Check which node is leader and whether leadership is stable.&lt;/li&gt;
&lt;li&gt;Confirm that a majority of voters can communicate.&lt;/li&gt;
&lt;li&gt;Inspect node restarts, CPU saturation, memory pressure, and disk latency.&lt;/li&gt;
&lt;li&gt;Check network latency and packet loss between members.&lt;/li&gt;
&lt;li&gt;Look at replication progress and log or snapshot activity.&lt;/li&gt;
&lt;li&gt;Compare client latency with commit latency.&lt;/li&gt;
&lt;li&gt;Read the service logs around term changes, rejected appends, and storage errors.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not fix election instability by blindly increasing timeouts. First determine whether the cluster has slow disks, overloaded nodes, network problems, or an unrealistic timeout configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failure testing
&lt;/h3&gt;

&lt;p&gt;A lab cluster is a good place to test failure behavior. With a disposable environment, you can try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stopping one follower.&lt;/li&gt;
&lt;li&gt;Restarting a follower after it has missed entries.&lt;/li&gt;
&lt;li&gt;Interrupting network connectivity between members.&lt;/li&gt;
&lt;li&gt;Restarting the leader.&lt;/li&gt;
&lt;li&gt;Observing what happens when a majority is unavailable.&lt;/li&gt;
&lt;li&gt;Restoring connectivity and watching lagging nodes catch up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each test, record what happened to write success, latency, leader identity, and recovery time. Do not run disruptive tests on a production cluster without a reviewed plan.&lt;/p&gt;




&lt;h2&gt;
  
  
  21. Common mistakes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Treating timeout as proof of failure
&lt;/h3&gt;

&lt;p&gt;A timeout means the expected response did not arrive in time. The remote operation may still have succeeded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; design retry behavior around operation IDs and idempotency where needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assuming replicas are always identical
&lt;/h3&gt;

&lt;p&gt;Replicas can have different uncommitted log suffixes or different applied positions. Raft allows temporary differences while preserving committed history.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; distinguish replication, commitment, and application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Thinking the leader can always accept writes
&lt;/h3&gt;

&lt;p&gt;A leader without a majority cannot commit new entries. It may still be running and reachable by some clients, but it cannot safely progress independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; monitor quorum and define client behavior when quorum is unavailable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assuming a majority alone explains all safety
&lt;/h3&gt;

&lt;p&gt;Quorums are central, but Raft also needs voting restrictions, log matching, terms, persistence, and the current-term commitment rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; understand the full path from election through log replication to commitment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forgetting durable storage
&lt;/h3&gt;

&lt;p&gt;If a node acknowledges protocol actions but loses required persistent state after a crash, safety assumptions can be violated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; follow the implementation's storage and persistence requirements. Treat fsync and write ordering as correctness concerns, not just performance tuning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serving every read from the leader without checking
&lt;/h3&gt;

&lt;p&gt;A node that believes it is leader may be isolated or stale. Read guarantees depend on the read protocol.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; use the implementation's documented linearizable-read mechanism when linearizable reads are required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Raft for everything
&lt;/h3&gt;

&lt;p&gt;Consensus adds coordination and requires a quorum. It is not needed for every cache, analytics pipeline, or stateless web service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; use consensus where a single agreed history is needed, and simpler designs where weaker guarantees are sufficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running an even number of voters to "get more availability"
&lt;/h3&gt;

&lt;p&gt;A four-voter cluster still needs three votes. It can tolerate only one unavailable voter, just like a three-voter cluster, while requiring more members to participate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Better:&lt;/strong&gt; choose the number and placement of voters based on failure domains and the system's documented recommendations.&lt;/p&gt;




&lt;h3&gt;
  
  
  What to remember
&lt;/h3&gt;

&lt;p&gt;Raft is not about making every node do everything independently. It is about agreeing on one ordered history, then applying that history consistently.&lt;/p&gt;

&lt;p&gt;The leader coordinates, the followers replicate, the quorum supports commitment, and the state machine applies committed commands. Elections and retries help the system recover, while the safety rules prevent temporary failures from turning into conflicting committed histories.&lt;/p&gt;




&lt;p&gt;Here is a clear, alphabetically organized glossary of key terms covered in your post, designed to be placed at the very end of your guide for a quick and easy reader review:&lt;/p&gt;

&lt;h2&gt;
  
  
  22. Quick Reference: Key Terms and Meanings
&lt;/h2&gt;

&lt;p&gt;Asynchronous Replication: A write mode where the primary node acknowledges a request immediately after saving it locally, without waiting for replicas to confirm receipt. Faster, but risks data loss if the primary fails.&lt;/p&gt;

&lt;p&gt;CAP Theorem: The rule stating that a distributed system can guarantee at most two of three properties during a network partition: Consistency, Availability, and Partition Tolerance.&lt;/p&gt;

&lt;p&gt;Clock Drift: The gradual discrepancy that develops between physical clocks on different machines over time, proving that physical timestamps alone cannot reliably order distributed events.&lt;/p&gt;

&lt;p&gt;Consensus: The fundamental problem of getting multiple independent nodes to agree on a single value or an ordered sequence of operations despite failures and message delays.&lt;/p&gt;

&lt;p&gt;Distributed System: A collection of independent computers connected over a network that communicate and coordinate to provide a single, unified service.&lt;/p&gt;

&lt;p&gt;Eventual Consistency: A weak consistency model where replicas temporarily diverge during updates but automatically converge over time once activity ceases.&lt;/p&gt;

&lt;p&gt;Idempotency: A property where an operation can be applied multiple times without changing the result beyond the initial application, preventing bugs from duplicate network retries.&lt;/p&gt;

&lt;p&gt;Leader Election: The process by which follower nodes timeout and vote to choose a new authoritative coordinator when the existing leader fails.&lt;/p&gt;

&lt;p&gt;Linearizability: A strong consistency model requiring all operations to appear atomic and instantaneous at a precise point in time between their invocation and response.&lt;/p&gt;

&lt;p&gt;Log Compaction (Snapshots): Truncating old log entries by saving the current state machine state to disk to prevent unbounded storage growth.&lt;/p&gt;

&lt;p&gt;Log Replication: The primary mechanism where the leader accepts client commands, appends them to its local log, and forces all follower nodes to match its history.&lt;/p&gt;

&lt;p&gt;Majority Quorum: The minimum number of operational nodes (⌊N/2⌋+1) required to safely make cluster decisions and commit logs.&lt;/p&gt;

&lt;p&gt;Partial Failure: A confusing state where one part of a system cannot determine whether another component is slow, crashed, or working properly.&lt;/p&gt;

&lt;p&gt;Partitioning (Sharding): Splitting a large dataset into distinct, manageable pieces distributed across multiple nodes to scale storage and throughput.&lt;/p&gt;

&lt;p&gt;Replication: Storing copies of data across multiple nodes to enhance durability, read capacity, and fault tolerance.&lt;/p&gt;

&lt;p&gt;Safety: A system guarantee ensuring that "nothing bad happens" (e.g., two leaders never commit conflicting values for the same log position).&lt;/p&gt;

&lt;p&gt;Split-Vote: An election failure scenario where votes are split evenly among multiple candidates, resolved in Raft using randomized timeouts.&lt;/p&gt;

&lt;p&gt;Synchronous Replication: A write mode where the primary node waits for a required majority of replicas to confirm a write before acknowledging success to the client.&lt;/p&gt;

&lt;p&gt;Term: Raft's logical clock counter used to divide time into discrete election epochs and detect obsolete leaders.&lt;/p&gt;

&lt;p&gt;Timeout: Evidence that a network response did not arrive in time, which indicates a potential failure but does not prove the underlying operation failed.&lt;/p&gt;




&lt;h2&gt;
  
  
  23. Further reading
&lt;/h2&gt;

&lt;p&gt;These are good places to go deeper into the protocol and its real implementations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://raft.github.io/raft.pdf" rel="noopener noreferrer"&gt;In Search of an Understandable Consensus Algorithm (Raft paper)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raft.github.io/" rel="noopener noreferrer"&gt;Raft visualization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://etcd.io/docs/" rel="noopener noreferrer"&gt;etcd documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://etcd.io/docs/latest/faq/" rel="noopener noreferrer"&gt;etcd FAQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.hashicorp.com/consul/docs/architecture/consensus" rel="noopener noreferrer"&gt;Consul consensus and Raft&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/" rel="noopener noreferrer"&gt;Kubernetes documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The original Raft paper is worth reading after you understand the basic roles, terms, log replication, and commitment rules. The figures and safety arguments explain why the protocol's restrictions exist, not just what messages get sent.&lt;/p&gt;




&lt;h2&gt;
  
  
  The End
&lt;/h2&gt;

&lt;p&gt;Distributed systems become easier to reason about when you stop assuming that every machine knows the same thing at the same time.&lt;/p&gt;

&lt;p&gt;Messages get delayed. Nodes fail. Logs temporarily differ. Raft gives a cluster a disciplined way to elect a leader, replicate commands, and decide which entries are safe to apply.&lt;/p&gt;

&lt;p&gt;The interesting part is how much depends on the details: quorum overlap, durable state, log freshness, commitment rules, and how clients behave when responses are lost. Those details are what turn a few machines connected over a network into a system that can be trusted.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>computerscience</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>i touched AWS and stuff didn't break (mostly)</title>
      <dc:creator>Ansh Dhanani</dc:creator>
      <pubDate>Wed, 27 May 2026 09:51:37 +0000</pubDate>
      <link>https://dev.to/dhanani_ansh/i-touched-aws-and-stuff-didnt-break-mostly-1cnm</link>
      <guid>https://dev.to/dhanani_ansh/i-touched-aws-and-stuff-didnt-break-mostly-1cnm</guid>
      <description>&lt;p&gt;so. i finally sat down and actually did AWS. not just watched tutorials, not just read docs actually clicked buttons, broke things, fixed them, and now i have opinions.&lt;/p&gt;

&lt;p&gt;this is a writeup of everything i learned practically in this last 1 week, in the order i learned it, with zero fluff. if you're someone who learns by doing and wants a no-nonsense walkthrough of core AWS concepts you're in the right place.&lt;/p&gt;

&lt;p&gt;let's go.&lt;/p&gt;




&lt;h2&gt;
  
  
  spinning up my first EC2 instance
&lt;/h2&gt;

&lt;p&gt;EC2 is basically "rent a computer from Amazon and it runs 24/7 somewhere in a data center." that's the whole thing. everything else is just configuration.&lt;/p&gt;

&lt;p&gt;i launched a &lt;code&gt;t3.micro&lt;/code&gt; in &lt;strong&gt;ap-south-1 (Mumbai)&lt;/strong&gt; free tier, which is perfect for learning. named it &lt;code&gt;my web server&lt;/code&gt; because i'm creative like that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;what actually matters when launching:&lt;/strong&gt; the AMI (think: OS), the instance type (think: hardware specs), and your key pair (SSH access). everything else can be changed later. don't overthink it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;once it's running, you get a public IPv4. EC2 Instance Connect lets you SSH directly from the browser which is actually very clean for beginners. no terminal setup needed.&lt;/p&gt;

&lt;p&gt;one thing that tripped me up the instance showed "Running" but that doesn't mean your &lt;em&gt;application&lt;/em&gt; is running. the VM is up, your code is not. different things.&lt;/p&gt;




&lt;h2&gt;
  
  
  deploying a "website" (lol)
&lt;/h2&gt;

&lt;p&gt;my first deployed website on AWS was literally this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hi, i am Ansh. and this is my first AWS based self deployed website. WOHOOOO!!! let's gooo!!!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;one line of HTML. serving it with nginx. accessible on port 80 over HTTP. it's terrible and i loved it.&lt;/p&gt;

&lt;p&gt;hitting that raw IP in the browser and seeing that text load that was a real moment. first cloud-deployed thing i've ever built. it's plain text and i don't care, it counts.&lt;/p&gt;

&lt;p&gt;the actual commands to get nginx running:&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="c"&gt;# update, install, start&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;nginx &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start nginx
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;nginx

&lt;span class="c"&gt;# drop your HTML here&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /var/www/html/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;that's literally it. the web server is now live. the hard part was not the code it was getting the networking right, which brings us to...&lt;/p&gt;




&lt;h2&gt;
  
  
  security groups - what even is a port?
&lt;/h2&gt;

&lt;p&gt;security groups are basically firewall rules for your EC2 instance. when i first tried hitting my instance's IP in the browser, nothing loaded. timeout. because i hadn't opened port 80 (HTTP).&lt;/p&gt;

&lt;p&gt;i set up a security group called &lt;code&gt;ssh-http-web-secgrp&lt;/code&gt; with two inbound rules:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. SSH on port 22&lt;/strong&gt; so i can connect to the instance via terminal. source: &lt;code&gt;0.0.0.0/0&lt;/code&gt; (anywhere) for learning, should be your IP in prod.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. HTTP on port 80&lt;/strong&gt; so the world can access the web server. source: the load balancer's security group, not the open internet. that is how security is built. we only allow what is needed, in this case the security group of the load balancer which is named &lt;code&gt;LB-SG&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;actually important thing:&lt;/strong&gt; security groups are &lt;em&gt;stateful&lt;/em&gt;. if you allow inbound on port 80, the response traffic goes out automatically. you don't need a matching outbound rule. this confused me for a bit.&lt;/p&gt;
&lt;/blockquote&gt;

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




&lt;h2&gt;
  
  
  launch templates + auto scaling groups (aka AWS spawning servers for me automatically)
&lt;/h2&gt;

&lt;p&gt;this was the point where AWS stopped feeling like "just a Linux VM in the cloud" and started feeling like actual cloud engineering.&lt;/p&gt;

&lt;p&gt;after setting up the load balancer, i wanted the infrastructure to react automatically when traffic increased. not manually launching EC2 instances every time the CPU cried for help.&lt;/p&gt;

&lt;p&gt;so i created a &lt;strong&gt;Launch Template&lt;/strong&gt; and connected it to an &lt;strong&gt;Auto Scaling Group (ASG).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;the mental model finally clicked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Launch Template&lt;/strong&gt; = blueprint for creating EC2 instances&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Scaling Group&lt;/strong&gt; = service that decides &lt;em&gt;when&lt;/em&gt; to create or terminate them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;the template stored everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu AMI&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t3.micro&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;security groups&lt;/li&gt;
&lt;li&gt;key pair&lt;/li&gt;
&lt;li&gt;nginx setup&lt;/li&gt;
&lt;li&gt;networking config&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;basically a reusable recipe for servers.&lt;/p&gt;

&lt;p&gt;instead of manually configuring instances forever, AWS can now just clone new ones automatically whenever needed.&lt;/p&gt;

&lt;p&gt;my ASG config looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minimum instances: 1
desired instances: 1
maximum instances: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which basically means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;always keep &lt;strong&gt;at least 1&lt;/strong&gt; server alive&lt;/li&gt;
&lt;li&gt;normally run &lt;strong&gt;1&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;but if traffic spikes, scale up to &lt;strong&gt;3&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and honestly, this is where cloud finally became interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  the architecture looked like this
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;internet
    ↓
Application Load Balancer
    ↓
Auto Scaling Group
   ↙          ↘
web-1        web-2
ap-south-1c ap-south-1a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;traffic comes into the ALB.&lt;/p&gt;

&lt;p&gt;the ALB distributes requests across healthy EC2 instances.&lt;/p&gt;

&lt;p&gt;CloudWatch monitors metrics like CPU usage.&lt;/p&gt;

&lt;p&gt;if usage crosses a threshold, the ASG launches another instance automatically using the Launch Template.&lt;/p&gt;

&lt;p&gt;very simple idea conceptually. insanely powerful in practice.&lt;/p&gt;




&lt;h2&gt;
  
  
  making AWS panic on purpose
&lt;/h2&gt;

&lt;p&gt;then came the fun part.&lt;/p&gt;

&lt;p&gt;i SSH'd into &lt;code&gt;web-1&lt;/code&gt; and intentionally tortured the CPU using the &lt;code&gt;stress&lt;/code&gt; tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;stress &lt;span class="nt"&gt;-y&lt;/span&gt;

stress &lt;span class="nt"&gt;--cpu&lt;/span&gt; 2 &lt;span class="nt"&gt;--timeout&lt;/span&gt; 600 &amp;amp;
stress &lt;span class="nt"&gt;--cpu&lt;/span&gt; 1 &lt;span class="nt"&gt;--timeout&lt;/span&gt; 600 &amp;amp;
stress &lt;span class="nt"&gt;--cpu&lt;/span&gt; 2 &lt;span class="nt"&gt;--timeout&lt;/span&gt; 60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;my scaling policy was configured around:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if CPU &amp;gt; 40%
→ launch another instance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then i just watched the dashboards.&lt;/p&gt;




&lt;h2&gt;
  
  
  watching auto scaling happen live
&lt;/h2&gt;

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

&lt;p&gt;the load balancer monitoring started showing request spikes and activity increasing as the stress test ran.&lt;/p&gt;




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

&lt;p&gt;CPU utilization climbed hard from basically idle.&lt;/p&gt;

&lt;p&gt;network traffic increased too because requests were flowing through the ALB into the instances.&lt;/p&gt;

&lt;p&gt;and then suddenly another EC2 instance appeared automatically.&lt;/p&gt;

&lt;p&gt;i did not press "Launch Instance."&lt;/p&gt;

&lt;p&gt;AWS launched it for me.&lt;/p&gt;




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

&lt;p&gt;this tiny terminal command triggered the whole scaling workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;high CPU load
    ↓
CloudWatch detects &amp;gt;40%
    ↓
Auto Scaling policy triggers
    ↓
Launch Template used
    ↓
new EC2 instance created
    ↓
Load Balancer adds healthy target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that feedback loop is the foundation of scalable cloud systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  the thing that changed how i think about servers
&lt;/h2&gt;

&lt;p&gt;before this, my brain thought scaling meant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"buy a bigger machine"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AWS teaches the opposite mindset.&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;you do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;many smaller servers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;horizontal scaling.&lt;/p&gt;

&lt;p&gt;because smaller machines are replaceable.&lt;/p&gt;

&lt;p&gt;if one dies? the ASG launches another.&lt;/p&gt;

&lt;p&gt;if traffic spikes? launch more.&lt;/p&gt;

&lt;p&gt;if traffic drops? terminate extras and save money.&lt;/p&gt;

&lt;p&gt;that's why load balancers matter so much. users don't connect directly to servers anymore. they connect to the ALB, and the ALB decides where traffic goes.&lt;/p&gt;

&lt;p&gt;instances become disposable infrastructure.&lt;/p&gt;

&lt;p&gt;and that is a VERY different way of thinking compared to traditional hosting.&lt;/p&gt;




&lt;h2&gt;
  
  
  honestly the coolest part
&lt;/h2&gt;

&lt;p&gt;the craziest thing is this entire setup was built using just:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EC2&lt;/li&gt;
&lt;li&gt;CloudWatch&lt;/li&gt;
&lt;li&gt;Load Balancer&lt;/li&gt;
&lt;li&gt;Launch Template&lt;/li&gt;
&lt;li&gt;Auto Scaling Group&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;no Kubernetes.&lt;/p&gt;

&lt;p&gt;no Docker orchestration.&lt;/p&gt;

&lt;p&gt;no Terraform.&lt;/p&gt;

&lt;p&gt;just core AWS services working together.&lt;/p&gt;

&lt;p&gt;and suddenly the infrastructure can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scale itself&lt;/li&gt;
&lt;li&gt;distribute traffic&lt;/li&gt;
&lt;li&gt;recover automatically&lt;/li&gt;
&lt;li&gt;survive instance failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;that's the first moment AWS actually felt like "the cloud" to me instead of just "Ubuntu running somewhere else."&lt;/p&gt;




&lt;h2&gt;
  
  
  IAM - learning what "not authorized" feels like
&lt;/h2&gt;

&lt;p&gt;IAM (Identity and Access Management) is AWS's permission system. users, roles, policies. this one bit me directly.&lt;/p&gt;

&lt;p&gt;i was poking around with a second AWS account and tried to view EC2 instances in eu-north-1 (Stockholm). got this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are not authorized to perform this operation.
User: arn:aws:iam::590128028909:user/Ansh-2 is not authorized
to perform: ec2:DescribeInstances because no identity-based
policy allows the ec2:DescribeInstances action
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;makes total sense in hindsight. the user had no IAM policies attached. by default in AWS you get nothing. zero permissions. you have to explicitly grant everything.&lt;/p&gt;

&lt;p&gt;this is the opposite of how most beginners think about it. they expect "allow everything by default, block what's dangerous." AWS does "block everything by default, allow what you need." way more secure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the IAM mental model:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;root account&lt;/strong&gt; = god mode. don't use it for daily stuff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM user&lt;/strong&gt; = a specific identity with attached policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;policy&lt;/strong&gt; = JSON document saying "this action on this resource is allowed/denied."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;role&lt;/strong&gt; = like a user but assumed temporarily (e.g., an EC2 instance acting as a user to access S3).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;the ARN (Amazon Resource Name) in that error message is how AWS identifies every resource uniquely. &lt;code&gt;arn:aws:iam::590128028909:user/Ansh-2&lt;/code&gt; = account ID + service + resource.&lt;/p&gt;

&lt;p&gt;you'll see ARNs everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  S3 - storing stuff in the cloud like a normal person
&lt;/h2&gt;

&lt;p&gt;S3 (Simple Storage Service) is object storage. not a file system, not a database just a bucket that holds objects (files). infinitely scalable, stupidly cheap, and the backbone of half the internet.&lt;/p&gt;

&lt;p&gt;i created a bucket called &lt;code&gt;first-s3-bucket-by-ansh&lt;/code&gt; in ap-south-1 and uploaded one image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;maykl-dzhekson-michael-jackson.jpg · 62.2 KB · Standard storage class
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(yes that's how it was spelled. yes i kept it.)&lt;/p&gt;

&lt;p&gt;first attempt to access it via the public URL, got this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Error&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Code&amp;gt;&lt;/span&gt;AccessDenied&lt;span class="nt"&gt;&amp;lt;/Code&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Message&amp;gt;&lt;/span&gt;Access Denied&lt;span class="nt"&gt;&amp;lt;/Message&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Error&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;because S3 buckets are private by default. again, AWS defaults to locked down.&lt;/p&gt;

&lt;p&gt;to make an object publicly accessible you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Disable "Block Public Access"&lt;/strong&gt; at the bucket level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a bucket policy&lt;/strong&gt; that allows &lt;code&gt;s3:GetObject&lt;/code&gt; for &lt;code&gt;Principal: "*"&lt;/code&gt; on the objects.&lt;/li&gt;
&lt;li&gt;or just hit &lt;strong&gt;"Make public"&lt;/strong&gt; on the individual object. faster for learning, wrong for production.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;after sorting that out, the image loaded. michael jackson silhouette on a black background, served from my S3 bucket and accessible from anywhere in the world.&lt;/p&gt;

&lt;p&gt;the URL structure is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://[bucket-name].s3.[region].amazonaws.com/[object-key]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;S3 is everywhere:&lt;/strong&gt; static website hosting, ML model weights, application logs, database backups, CDN origin... you'll use S3 in basically every AWS architecture. understand it early.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  tldr / what i actually learned
&lt;/h2&gt;

&lt;p&gt;not just "what buttons to click" the mental models that stuck:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS defaults to deny.&lt;/strong&gt; no permissions, no access. you build up from zero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Availability zones are not optional.&lt;/strong&gt; run across at least two if anything needs to stay up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security groups are stateful firewalls.&lt;/strong&gt; inbound rules are enough for most setups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load balancers + auto scaling = resilience.&lt;/strong&gt; don't make your instance bigger, make more of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IAM is the foundation.&lt;/strong&gt; understanding ARNs, policies, and roles unlocks everything else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 is not just file storage.&lt;/strong&gt; it's an architecture primitive.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;what's next:&lt;/strong&gt; RDS for a proper database, CloudFront for CDN, and Route 53 for a real domain instead of raw IP addresses.&lt;/p&gt;

&lt;p&gt;also i need to terminate these instances before my free tier runs out.&lt;/p&gt;

&lt;p&gt;- Ansh Dhanani&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Accidentally Found a Better Way to Get effective results from AI Agents</title>
      <dc:creator>Ansh Dhanani</dc:creator>
      <pubDate>Fri, 15 May 2026 07:32:41 +0000</pubDate>
      <link>https://dev.to/dhanani_ansh/i-accidentally-found-a-better-way-to-use-and-get-better-results-from-ai-agents-2b08</link>
      <guid>https://dev.to/dhanani_ansh/i-accidentally-found-a-better-way-to-use-and-get-better-results-from-ai-agents-2b08</guid>
      <description>&lt;h2&gt;
  
  
  The Problem I Kept Running Into
&lt;/h2&gt;

&lt;p&gt;Recently I was experimenting with different ways of using AI agents on larger projects and I found a workflow that gives surprisingly better results than normal prompting.&lt;/p&gt;

&lt;p&gt;Usually when people use tools like Claude or ChatGPT for coding, they paste a few snippets or files and ask questions directly. That works fine for smaller problems, but once the project becomes bigger, the outputs start getting inconsistent. Sometimes the AI misses obvious architectural problems, sometimes it suggests things that don’t fit the system at all, and sometimes it completely loses track of how different parts of the codebase interact.&lt;/p&gt;

&lt;p&gt;After testing this for a while, I realized the issue is usually not the model itself.&lt;/p&gt;

&lt;p&gt;The issue is context.&lt;/p&gt;

&lt;p&gt;Most current AI coding workflows rely on fragmented context. The model only sees disconnected chunks of the system, so it never develops a real understanding of execution flow, runtime behavior, dependency direction or how services interact together.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Workflow I Started Using
&lt;/h2&gt;

&lt;p&gt;So I tried something different.&lt;/p&gt;

&lt;p&gt;I wrote a small script that scans my repository and bundles important files into one large file. Not literally every file, because that creates too much noise, but the parts that actually explain how the system works. Things like schemas, orchestration logic, parsers, graph systems, runtime handling, caching, workers, dependency management and other core logic.&lt;/p&gt;

&lt;p&gt;Then instead of directly asking Claude to analyze the codebase, I first use ChatGPT to generate a much deeper investigation prompt.&lt;/p&gt;

&lt;p&gt;Not generic prompts like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“find bugs”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But prompts focused on things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;architectural analysis&lt;/li&gt;
&lt;li&gt;performance bottlenecks&lt;/li&gt;
&lt;li&gt;scaling risks&lt;/li&gt;
&lt;li&gt;hidden coupling&lt;/li&gt;
&lt;li&gt;unnecessary abstractions&lt;/li&gt;
&lt;li&gt;memory pressure&lt;/li&gt;
&lt;li&gt;concurrency issues&lt;/li&gt;
&lt;li&gt;runtime inefficiencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I paste both the bundled code file and the generated investigation prompt into Claude.&lt;/p&gt;

&lt;p&gt;The difference in output quality is honestly huge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Think This Works
&lt;/h2&gt;

&lt;p&gt;The model starts reasoning about the system much more coherently because it can actually see relationships between different layers of the application.&lt;/p&gt;

&lt;p&gt;It starts identifying patterns that are difficult to notice when looking at isolated files — duplicated logic, circular dependencies, architectural inconsistencies, bad retry handling, unnecessary complexity and hidden performance issues.&lt;/p&gt;

&lt;p&gt;What became interesting to me is that this doesn’t really feel like “better prompting”.&lt;/p&gt;

&lt;p&gt;It feels more like giving the model enough architectural visibility to reason properly.&lt;/p&gt;

&lt;p&gt;I think a lot of current AI tools behave like they’re trying to understand a large system while only seeing tiny windows into it. Once the model can access enough of the architecture at once, the quality of reasoning changes significantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where This Approach Breaks
&lt;/h2&gt;

&lt;p&gt;I also noticed there’s a limit to this approach.&lt;/p&gt;

&lt;p&gt;If you dump too much irrelevant information into context — logs, generated files, lockfiles, vendor code, build artifacts and other noisy files — the quality drops again. The model starts focusing on the wrong things or missing important details completely.&lt;/p&gt;

&lt;p&gt;So now I’ve been experimenting more with what I’d call context engineering instead of just prompt engineering.&lt;/p&gt;

&lt;p&gt;Another thing that improved results a lot was feeding structural information before the raw code itself. Things like dependency graphs, import relationships, architecture overviews and execution flow maps help the model build a mental representation of the system before reading implementation details.&lt;/p&gt;

&lt;p&gt;That alone improved the consistency of outputs quite a bit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Context Engineering &amp;gt; Prompt Engineering
&lt;/h2&gt;

&lt;p&gt;Honestly, I think this is where AI-assisted development tools are heading.&lt;/p&gt;

&lt;p&gt;Not just bigger models, but better context systems.&lt;/p&gt;

&lt;p&gt;Right now most coding agents still behave like they’re reading code through a keyhole. They only see tiny sections at a time, which makes deeper reasoning difficult on larger projects.&lt;/p&gt;

&lt;p&gt;Once the model can understand more of the system at once, the analysis becomes much more useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;debugging&lt;/li&gt;
&lt;li&gt;architecture reviews&lt;/li&gt;
&lt;li&gt;performance analysis&lt;/li&gt;
&lt;li&gt;scaling research&lt;/li&gt;
&lt;li&gt;understanding unfamiliar codebases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This workflow still has limitations and it definitely doesn’t magically solve hallucinations or reasoning errors.&lt;/p&gt;

&lt;p&gt;But compared to normal snippet-based prompting, the results have been noticeably better.&lt;/p&gt;




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

&lt;p&gt;I’m curious if other people are experimenting with similar workflows too, because it feels like we’re still very early in figuring out how AI should actually interact with large codebases.&lt;/p&gt;

&lt;p&gt;A lot of people are focused on better models, but I think context handling is becoming just as important.&lt;/p&gt;

&lt;p&gt;And honestly, whoever solves context engineering properly is probably going to build extremely powerful developer tools.&lt;/p&gt;




</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Building My First Self-Hosted Infrastructure Server on Linux</title>
      <dc:creator>Ansh Dhanani</dc:creator>
      <pubDate>Wed, 13 May 2026 16:23:21 +0000</pubDate>
      <link>https://dev.to/dhanani_ansh/building-my-first-self-hosted-infrastructure-server-on-linux-7c7</link>
      <guid>https://dev.to/dhanani_ansh/building-my-first-self-hosted-infrastructure-server-on-linux-7c7</guid>
      <description>&lt;p&gt;I always thought Linux looked cool from the outside, but I never really understood why developers became obsessed with it until I actually started using it properly.&lt;/p&gt;

&lt;p&gt;For most of my life, I was just a normal Windows 10 user. My workflow was simple VS Code, browsers, localhost development, and deploying apps without thinking too much about what was happening underneath. Everything worked, but after building more projects, especially AI and web applications, I started feeling disconnected from the actual systems running my applications.&lt;/p&gt;

&lt;p&gt;I knew how to build projects.&lt;/p&gt;

&lt;p&gt;I didn’t know how infrastructure worked.&lt;/p&gt;

&lt;p&gt;That’s when I started exploring Linux seriously.&lt;/p&gt;




&lt;h2&gt;
  
  
  Discovering Omarchy
&lt;/h2&gt;

&lt;p&gt;After trying different Linux distributions, I found Omarchy and instantly liked it. The system felt extremely fast, minimal, and surprisingly clean. Compared to Windows, everything felt more focused. The terminal experience, window management, keyboard shortcuts, and multiple pane workflow completely changed how I worked.&lt;/p&gt;

&lt;p&gt;The coolest part was how efficient everything felt once you got comfortable with it.&lt;/p&gt;

&lt;p&gt;I used Omarchy for around two months before eventually breaking the entire setup. One bad configuration later, none of the UI loaded anymore and I was left staring at a shell screen with absolutely no idea how to recover the system properly.&lt;/p&gt;

&lt;p&gt;That moment honestly taught me something important.&lt;/p&gt;

&lt;p&gt;Linux gives you freedom, but it also expects responsibility.&lt;/p&gt;

&lt;p&gt;Even after breaking everything though, I still loved the experience enough to come back again. This time I decided to run Omarchy inside VirtualBox on Windows 10 so I could safely experiment without destroying my main environment again.&lt;/p&gt;

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




&lt;h1&gt;
  
  
  Setting Up the VM
&lt;/h1&gt;

&lt;p&gt;Once the virtual machine was running, I finally had a playground where I could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;experiment freely&lt;/li&gt;
&lt;li&gt;break things safely&lt;/li&gt;
&lt;li&gt;learn networking&lt;/li&gt;
&lt;li&gt;build servers manually&lt;/li&gt;
&lt;li&gt;understand infrastructure properly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal was simple:&lt;/p&gt;

&lt;p&gt;Build a small self-hosted infrastructure setup using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;load balancing&lt;/li&gt;
&lt;li&gt;networking&lt;/li&gt;
&lt;li&gt;benchmarking&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Installing Nginx and Creating the Project
&lt;/h1&gt;

&lt;p&gt;Docker was already included with Omarchy, so I mainly needed Nginx.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I created the project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;nginx-lb
&lt;span class="nb"&gt;cd &lt;/span&gt;nginx-lb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the folder I created:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 web apps&lt;/li&gt;
&lt;li&gt;an Nginx config&lt;/li&gt;
&lt;li&gt;a Docker Compose setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The structure looked like this:&lt;/p&gt;

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

&lt;p&gt;Each app simply had an &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  app1/index.html
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;App 1&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  app2/index.html
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;App 2&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  app3/index.html
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;App 3&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, but enough to visually verify load balancing.&lt;/p&gt;




&lt;h1&gt;
  
  
  Docker Compose Setup
&lt;/h1&gt;

&lt;p&gt;Then I created the Docker Compose configuration using &lt;code&gt;nano&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Omarchy already comes with NeoVim pre-installed, and honestly the setup looks extremely cool. Once you get comfortable with it, the workflow feels insanely fast. But in real server environments, especially when you're quickly editing configs over SSH, you'll often see people using something simple like &lt;code&gt;nano&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It’s quick, lightweight, always available, and efficient for fast configuration changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./app1:/usr/share/nginx/html&lt;/span&gt;

  &lt;span class="na"&gt;app2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./app2:/usr/share/nginx/html&lt;/span&gt;

  &lt;span class="na"&gt;app3&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./app3:/usr/share/nginx/html&lt;/span&gt;

  &lt;span class="na"&gt;nginx-lb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-lb&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx/nginx.conf:/etc/nginx/nginx.conf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point I finally started understanding why containers are so important.&lt;/p&gt;

&lt;p&gt;Everything became isolated, reproducible, and easy to manage.&lt;/p&gt;




&lt;h1&gt;
  
  
  Understanding Load Balancing Through Nginx
&lt;/h1&gt;

&lt;p&gt;This was probably the coolest part of the entire project.&lt;/p&gt;

&lt;p&gt;The Nginx configuration looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;events&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kn"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;app1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;app2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;app3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://backend&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;That tiny file completely changed how I viewed backend systems.&lt;/p&gt;

&lt;p&gt;Instead of one server handling everything, Nginx distributes requests between multiple backend containers.&lt;/p&gt;

&lt;p&gt;This is load balancing.&lt;/p&gt;

&lt;p&gt;Not theory anymore.&lt;/p&gt;

&lt;p&gt;An actual working system running inside my VM.&lt;/p&gt;

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




&lt;h1&gt;
  
  
  Running the Containers
&lt;/h1&gt;

&lt;p&gt;Once everything was ready, I started the infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The containers started successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when I opened localhost inside the VM, different apps started appearing depending on which backend handled the request.&lt;/p&gt;

&lt;p&gt;That moment felt genuinely satisfying because I wasn’t just running applications anymore.&lt;/p&gt;

&lt;p&gt;I was running infrastructure.&lt;/p&gt;

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




&lt;h1&gt;
  
  
  NAT vs Bridged Adapter
&lt;/h1&gt;

&lt;p&gt;This part confused me for hours.&lt;/p&gt;

&lt;p&gt;The setup worked perfectly inside the VM, but Windows couldn’t access it initially.&lt;/p&gt;

&lt;p&gt;That’s when I learned about NAT and Bridged networking.&lt;/p&gt;




&lt;h2&gt;
  
  
  NAT + Port Forwarding
&lt;/h2&gt;

&lt;p&gt;NAT creates an isolated internal network for the VM.&lt;/p&gt;

&lt;p&gt;The host machine cannot directly access the virtual machine unless ports are forwarded manually.&lt;/p&gt;

&lt;p&gt;So I configured port forwarding in VirtualBox like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Host Port: &lt;code&gt;8080&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Guest Port: &lt;code&gt;80&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which basically meant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows localhost:8080 -&amp;gt; VM port 80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After configuring this properly, I could finally access the Nginx load balancer directly from Windows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bridged Adapter
&lt;/h2&gt;

&lt;p&gt;Bridged mode felt even cooler.&lt;/p&gt;

&lt;p&gt;Instead of staying inside an isolated virtual network, the VM became a real device on my local network and got its own IP address.&lt;/p&gt;

&lt;p&gt;Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;/div&gt;



&lt;p&gt;Now I could directly access the server from Windows using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://10.93.5.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That honestly felt insane the first time it worked.&lt;/p&gt;

&lt;p&gt;Networking finally stopped feeling abstract.&lt;/p&gt;




&lt;h1&gt;
  
  
  Stress Testing With wrk
&lt;/h1&gt;

&lt;p&gt;Now came the fun part.&lt;/p&gt;

&lt;p&gt;Benchmarking the infrastructure.&lt;/p&gt;

&lt;p&gt;I used &lt;code&gt;wrk&lt;/code&gt; to generate traffic and test how the setup behaved with different numbers of backend containers behind the Nginx load balancer.&lt;/p&gt;

&lt;p&gt;The command I used was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wrk &lt;span class="nt"&gt;-t4&lt;/span&gt; &lt;span class="nt"&gt;-c100&lt;/span&gt; &lt;span class="nt"&gt;-d30&lt;/span&gt; http://127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-t4&lt;/code&gt; → 4 threads&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-c100&lt;/code&gt; → 100 concurrent connections&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-d30&lt;/code&gt; → run test for 30 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting part was comparing the performance between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 backend container&lt;/li&gt;
&lt;li&gt;2 backend containers&lt;/li&gt;
&lt;li&gt;3 backend containers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1 Container Test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Running 30s test @ http://127.0.0.1
4 threads and 100 connections

Thread Stats   Avg      Stdev     Max   +/- Stdev
Latency    21.78ms   28.04ms 238.82ms   86.21%
Req/Sec     1.36k     1.06k    8.34k    75.55%

141456 requests in 30.05s, 34.13MB read

Socket errors: connect 0, read 0, write 0, timeout 102

Requests/sec:   4706.85
Transfer/sec:      1.14MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a single backend container, the setup still handled a surprisingly large amount of traffic. But the latency was noticeably higher and there were some request timeouts under heavy load.&lt;/p&gt;




&lt;h2&gt;
  
  
  2 Container Test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Running 30s test @ http://127.0.0.1
4 threads and 100 connections

Thread Stats   Avg      Stdev     Max   +/- Stdev
Latency    10.39ms   10.07ms 146.04ms   89.23%
Req/Sec     1.76k     1.01k    6.95k    82.19%

110705 requests in 30.10s, 26.71MB read

Socket errors: connect 0, read 0, write 0, timeout 100

Requests/sec:   3678.10
Transfer/sec:      0.89MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a second backend container reduced the average latency significantly. The load balancer was now distributing traffic across multiple services instead of pushing everything into a single container.&lt;/p&gt;

&lt;p&gt;Even though the requests/sec result was lower during this run, the overall responsiveness and latency consistency improved.&lt;/p&gt;




&lt;h2&gt;
  
  
  3 Container Test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Thread Stats   Avg      Stdev     Max   +/- Stdev
Latency    13.85ms   11.87ms 247.23ms   87.54%
Req/Sec     1.74k   672.33     6.35k    75.85%

207100 requests in 30.03s, 49.97MB read

Requests/sec:   6895.35
Transfer/sec:      1.66MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With three backend containers running behind Nginx, the setup handled the highest total request throughput.&lt;/p&gt;

&lt;p&gt;This was the point where load balancing finally felt real to me.&lt;/p&gt;

&lt;p&gt;Instead of one application trying to handle everything alone, requests were being distributed across multiple backend services. Even inside a small VM setup, you could clearly see how scaling horizontally changes system behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned From Benchmarking
&lt;/h2&gt;

&lt;p&gt;The most interesting part wasn’t just the numbers.&lt;/p&gt;

&lt;p&gt;It was understanding the concept behind them.&lt;/p&gt;

&lt;p&gt;Before this, “scaling” always sounded like some massive enterprise topic only huge companies cared about. But after running these tests manually, I finally understood the core idea:&lt;/p&gt;

&lt;p&gt;Instead of making one server infinitely stronger, you can distribute traffic across multiple smaller services.&lt;/p&gt;

&lt;p&gt;That’s basically the foundation of modern infrastructure.&lt;/p&gt;




&lt;h1&gt;
  
  
  What I Learned
&lt;/h1&gt;

&lt;p&gt;The biggest thing I learned from this entire process is how much complexity modern platforms hide from developers.&lt;/p&gt;

&lt;p&gt;When we deploy apps today, we rarely think about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reverse proxies&lt;/li&gt;
&lt;li&gt;ports&lt;/li&gt;
&lt;li&gt;traffic routing&lt;/li&gt;
&lt;li&gt;containers&lt;/li&gt;
&lt;li&gt;networking&lt;/li&gt;
&lt;li&gt;load balancing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But building things manually teaches an entirely different level of understanding.&lt;/p&gt;

&lt;p&gt;I also realized infrastructure engineering feels very different from normal application development. A lot of the work is debugging, configuration, networking, and slowly understanding how systems communicate with each other.&lt;/p&gt;

&lt;p&gt;Sometimes nothing works for hours.&lt;/p&gt;

&lt;p&gt;Sometimes you break your entire Linux setup.&lt;/p&gt;

&lt;p&gt;Sometimes networking feels cursed.&lt;/p&gt;

&lt;p&gt;But when everything finally connects together correctly, it feels incredibly rewarding.&lt;/p&gt;

&lt;p&gt;And honestly, building a self-hosted infrastructure server inside a Linux VM might be one of the coolest things I’ve learned so far.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>docker</category>
      <category>nginx</category>
      <category>devops</category>
    </item>
    <item>
      <title>Shipping Faster in Full-Stack Development (2026) with AI Orchestration</title>
      <dc:creator>Ansh Dhanani</dc:creator>
      <pubDate>Wed, 28 Jan 2026 10:57:34 +0000</pubDate>
      <link>https://dev.to/dhanani_ansh/shipping-faster-in-full-stack-development-2026-with-ai-orchestration-8ck</link>
      <guid>https://dev.to/dhanani_ansh/shipping-faster-in-full-stack-development-2026-with-ai-orchestration-8ck</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqfdz0j1g6ybm7441ziq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqfdz0j1g6ybm7441ziq.png" alt=" " width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why it matters?
&lt;/h1&gt;

&lt;p&gt;lets say we have two guys. Where one is a giga chad coder guy who writes all code by himself and if he get stuck he just see docs. second is my type of guy who is a vibe-coder but not any other vibe-coder a Efficiency-level-V vibe-coder (I'll tell you why).&lt;/p&gt;

&lt;p&gt;so here is a thing, when they both start a big project. the giga chad starts from scratch and write everything which is not a bad thing also he knows every whys of his code, but after all this talk about giga chad if you see at the other one, he had already completed 90% of project with all best practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  how did he do that?
&lt;/h2&gt;

&lt;p&gt;that's what you'll learn in this blog later.&lt;/p&gt;

&lt;h2&gt;
  
  
  so who is better?
&lt;/h2&gt;

&lt;p&gt;there was a time when AI was not that impactful and people said its better to write slow and by own than from an AI assistance. but time is changed now yesterday an "open source model Kimi k2" by Moonshot AI just released and benchmark said it even better than claude opus 4.5. let me remind you claude opus 4.5 is a devil of coding complex logic.&lt;/p&gt;

&lt;p&gt;so, what i'm trying to say is, if you really know how to orchestrate this models you can actually ship products faster and more importantly robust.&lt;/p&gt;

&lt;h1&gt;
  
  
  here's how you can do it too.
&lt;/h1&gt;

&lt;p&gt;if you are a college student, you can get github pro using you college id and use some monthly free premium credits of claude sonnet 4.5 for free (thanks github). it also give other models but claude sonnet 4.5 is best among them.&lt;/p&gt;

&lt;p&gt;now you have claude waiting to be used.&lt;/p&gt;

&lt;p&gt;Lets dive into the best practices i used for best results.&lt;/p&gt;




&lt;h3&gt;
  
  
  Point 1: learn how to prompt efficiently.
&lt;/h3&gt;

&lt;p&gt;when i was in early stage of learning ai agents for coding, i used to tell chatgpt "hey chatgpt fix this error." back then, it wasn't even able to get the problem to start with.&lt;/p&gt;

&lt;p&gt;as i keep playing with it i come to know that you have to give full context about the problem or the thing you it to do. you have to keep in mind you have to give one prompt in which you have to write the clear problem and what path to follow and what not to too.&lt;/p&gt;

&lt;p&gt;for example:&lt;/p&gt;

&lt;p&gt;bad one:&lt;br&gt;
“Fix the backend bug.”&lt;/p&gt;

&lt;p&gt;Better prompt (structured):&lt;br&gt;
“In our Express + Prisma backend, the POST /users endpoint fails when email already exists. Prisma throws a unique constraint error. We want to return a 409 response instead of crashing the server. Suggest a fix and include proper error handling patterns.”&lt;/p&gt;

&lt;p&gt;remember to give full context weather it is about the error on browser console, typescript error ,compilation fails, refactor (very problematic) everything that you think it should know about everything. as a developer you must know how every thing works and why you choose what and all. you can't just let it do anything it wants, it will be just another useless slop and waste of credits.&lt;/p&gt;

&lt;p&gt;you should utilized each and every feature of you IDE. many people says cursor is better. let me tell you i have tried cursor, windsurf, lazy vim, emacs(Salute to those who use this), Jetbrain(nice one) and of course my personal favorite VS code. and i can tell you that it doesn't actually matters that much.&lt;/p&gt;

&lt;p&gt;talking about vs code features, you must use include files or folder in prompt feature(present in most IDEs) you want to change. you must be aware what you are give access, turns out you just expose your .env secrets and now openai asking you for 2421$ lol. also there are bunch of nice extentions which are very useful, you can check that out too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Point 2: Never start from scratch.
&lt;/h3&gt;

&lt;p&gt;if you are in any hackathon or starting any projects by your own (here i'm not talking about yt toutorials projects).&lt;/p&gt;

&lt;p&gt;IT IS BETTER TO START WITH TEMPLATE.&lt;/p&gt;

&lt;p&gt;you might be thinking that this is laziness. but let me tell you something, lazy smart coders are the best category of coders. They are the one who find short and best pathways using their laziness. funny but its fact.&lt;/p&gt;

&lt;p&gt;so, you might ask me Ansh where can we find clean templates for starters,&lt;br&gt;
as a developer if we talk about nextjs specifically, vercel have pretty nice templates. but you can find you perfect match from github too (i know it is little slow process but sometimes you can get a gem).&lt;/p&gt;

&lt;p&gt;I’m participating in a hackathon at IIT Gandhinagar with my team, and we needed to create an admin dashboard for our problem statement. What I did was use a ready-made shadcn admin dashboard template. I then used Claude Desktop and connected it with Desktop MCP, writing a big prompt that detailed everything we wanted in a &lt;code&gt;markdown.md&lt;/code&gt; file — basically everything about the problem, the tech stack, and the libraries to use. I kept an eye on it to make sure nothing went wrong. Now we have a clean project that doesn’t break.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Librarys.
&lt;/h2&gt;

&lt;p&gt;let's say you have a very nice project you working on, and you have to add a feature, the problem is you don't know how to do it.&lt;/p&gt;

&lt;p&gt;depending upon size and complexity of the feature, you sometime might not need any library, but if you have a big feature and you are supposed to handle many states at ones or anything complex, you must use a library rather than just asking ai to impliment it. it happens with me countless times that i asked it to implement a simple feature and it create all hooks and library fuctions inside component file, while i am having a separate clean structure to handle both types of files, but the ai doesn't know about my folder structure at all it just know that one component.&lt;/p&gt;

&lt;h1&gt;
  
  
  conclusion
&lt;/h1&gt;

&lt;p&gt;The giga chad's way works for adding critical features to already going projects.&lt;/p&gt;

&lt;p&gt;For project foundation and clean start you must follow efficient vibe coder way.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>HTTP Protocol Explained: The Complete Practical Guide for Developers</title>
      <dc:creator>Ansh Dhanani</dc:creator>
      <pubDate>Sun, 28 Dec 2025 12:33:59 +0000</pubDate>
      <link>https://dev.to/dhanani_ansh/as-a-developer-this-is-all-you-need-to-know-about-the-http-protocol-23ld</link>
      <guid>https://dev.to/dhanani_ansh/as-a-developer-this-is-all-you-need-to-know-about-the-http-protocol-23ld</guid>
      <description>&lt;h1&gt;
  
  
  The HTTP Guide for Developers
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;A practical guide to HTTP. No fluff-just what you need to build better applications and debug faster.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is HTTP?&lt;/li&gt;
&lt;li&gt;Why HTTP Matters&lt;/li&gt;
&lt;li&gt;HTTP Versions&lt;/li&gt;
&lt;li&gt;HTTP Messages&lt;/li&gt;
&lt;li&gt;HTTP Headers&lt;/li&gt;
&lt;li&gt;HTTP Methods&lt;/li&gt;
&lt;li&gt;Status Codes&lt;/li&gt;
&lt;li&gt;Idempotency&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;Content Negotiation&lt;/li&gt;
&lt;li&gt;Compression&lt;/li&gt;
&lt;li&gt;Persistent Connections&lt;/li&gt;
&lt;li&gt;Streaming&lt;/li&gt;
&lt;li&gt;HTTPS&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What is HTTP?
&lt;/h2&gt;

&lt;p&gt;HTTP (HyperText Transfer Protocol) is the fundamental language that powers the entire web. Think of it as the universal translator that allows your browser, mobile apps, and backend services to communicate with servers across the internet. Every time you load a website, check your email, or scroll through social media, HTTP is working behind the scenes, shuttling data back and forth in a structured, predictable way.&lt;/p&gt;

&lt;p&gt;At its core, HTTP operates on a beautifully simple principle: one device asks for something (the client), and another device responds with that thing (the server). This request-response model is what makes the web work. When you type a URL into your browser or your app fetches data from an API, that's an HTTP request flying across the network. The server processes that request and sends back an HTTP response containing the data you asked for-or an error message if something went wrong.&lt;/p&gt;

&lt;p&gt;Here's what a basic interaction looks like:&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your Browser  →  "GET /users/123 HTTP/1.1 headers..."  →  Server
Your Browser  ←  "HTTP/1.1 200 OK headers... {data}"   ←  Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The beauty of HTTP is that it's &lt;strong&gt;text-based&lt;/strong&gt; (in HTTP/1.x), which means humans can actually read and understand what's being sent. This makes debugging infinitely easier compared to binary protocols where you're staring at gibberish. You can literally open your browser's developer tools right now, go to the Network tab, and watch HTTP messages flying back and forth in real-time. Try it it's oddly satisfying.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Statelessness
&lt;/h3&gt;

&lt;p&gt;Now here's where HTTP gets interesting: it's &lt;strong&gt;stateless&lt;/strong&gt;, meaning the server has zero memory of previous requests. Each request is treated as a completely fresh interaction, as if the server has never met you before. This might sound like a limitation at first and honestly, it can be frustrating when you're starting out but it's actually one of HTTP's greatest strengths.&lt;/p&gt;

&lt;p&gt;Why? Because statelessness makes scaling trivial. If every request is independent, any server in a cluster can handle any request. You don't need "sticky sessions" or complex state synchronization between servers. User sends Request A to Server 1? Cool. Request B goes to Server 2? Also fine. The servers don't need to coordinate because there's no state to keep track of.&lt;/p&gt;

&lt;p&gt;Let's see this in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Request 1: &lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/cart&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"What cart? And first of all, who are you?"&lt;/span&gt;

Request 2: GET /cart HTTP/1.1  
Response: "Still don't know you. Who dis?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how do websites "remember" you? They cheat. We add state back using &lt;strong&gt;cookies&lt;/strong&gt; or &lt;strong&gt;tokens&lt;/strong&gt;. The server gives you a unique identifier (like a session ID), and you send it with every request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/cart&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;session_id=abc123&lt;/span&gt;

Response: "Ah yes, session abc123! Here's your cart with 3 items."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server looks up your session ID in a database (like Redis) and retrieves your cart data. Boom stateful behavior built on a stateless protocol. It's like showing your ID card every time you enter a building instead of the security guard remembering your face.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Request-Response Contract
&lt;/h3&gt;

&lt;p&gt;HTTP follows a strict contract: the client always initiates, the server always responds. The server never sends unsolicited data (that's what WebSockets are for). This asymmetry keeps things simple and predictable. Every HTTP conversation follows the same dance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client opens connection&lt;/strong&gt; (usually TCP on port 80 or 443)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client sends request&lt;/strong&gt; ("I want this resource")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server processes request&lt;/strong&gt; (database queries, business logic, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server sends response&lt;/strong&gt; ("Here's what you asked for" or "Nope, can't do that")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection closes&lt;/strong&gt; (or stays open for more requests)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This predictable pattern is why HTTP is so reliable. There's no ambiguity about who's talking when, no complex state machines to debug. Request comes in, response goes out. Simple. Elegant. Effective.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why HTTP Matters
&lt;/h2&gt;

&lt;p&gt;Imagine trying to build the internet without a standard protocol. Every website would invent its own communication rules, every API would require a custom client, and developers would spend more time writing protocol adapters than building actual features. It would be absolute chaos like trying to have a conversation where everyone speaks a different language with no translators available.&lt;/p&gt;

&lt;p&gt;HTTP solved this problem by giving us a universal standard. Whether you're talking to GitHub's API, Stripe's payment system, or your own backend, the protocol is identical. Same request format, same response structure, same status codes, same headers. This standardization is so fundamental to the web that we take it for granted, but it's genuinely revolutionary. One &lt;code&gt;fetch()&lt;/code&gt; call works for thousands of different services:&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;// Same exact pattern, completely different services&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.github.com/users/octocat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.stripe.com/v1/charges&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://yourcompany.com/api/orders&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;No special configuration, no custom libraries, no protocol negotiation just HTTP. This is the magic of standardization.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Hidden Benefits You Get for Free
&lt;/h3&gt;

&lt;p&gt;When you use HTTP, you're not just getting a protocol you're getting an entire ecosystem that has evolved over 30+ years. &lt;strong&gt;Built-in caching&lt;/strong&gt; means browsers and CDNs automatically cache your responses if you set the right headers. You don't need to build a caching layer; it's already there, waiting for you to use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: public, max-age=3600
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single header tells every intermediary between your server and the user to cache this response for an hour. Millions of requests saved, zero extra code written. That's leverage.&lt;/p&gt;

&lt;p&gt;Then there's the &lt;strong&gt;tooling ecosystem&lt;/strong&gt;. Because HTTP is standardized, we have incredible tools that work with any HTTP service: browser DevTools show you every request with full headers and timing information, Postman lets you craft complex API requests with a GUI, cURL gives you command-line superpowers, and monitoring tools like DataDog can analyze HTTP traffic patterns across your entire infrastructure. All of this exists because HTTP is standardized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Statelessness: The Scalability Superpower
&lt;/h3&gt;

&lt;p&gt;Here's where HTTP's stateless design becomes a massive advantage. In the old days, servers used to maintain session state in memory. This worked fine for small applications, but it created a nightmare for scaling. If Server A knew about your session but Server B didn't, load balancers had to implement "sticky sessions" to route all your requests to Server A. This meant uneven load distribution, difficult failover, and complex infrastructure.&lt;/p&gt;

&lt;p&gt;HTTP's statelessness cuts through this complexity like a hot knife through butter. Because each request is independent, any server can handle any request. Your first request goes to Server 1 in California? Cool. Your next request goes to Server 2 in Virginia? Also fine. Neither server needs to know about the other, and both can process your request by looking up your session token in a shared database.&lt;/p&gt;

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

&lt;p&gt;This architecture is simple, reliable, and scales horizontally. Need more capacity? Spin up more servers. No complex state synchronization, no session migration, no headaches. This is why modern web applications can serve millions of users HTTP's stateless design makes it almost trivially easy to scale.&lt;/p&gt;

&lt;p&gt;When you combine all these benefits universal compatibility, free caching, incredible tooling, and effortless scaling you start to understand why HTTP has dominated the web for three decades and shows no signs of going away. It's not just a protocol; it's the foundation that makes the entire internet economy possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  HTTP Versions: Evolution Through Real Problems
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What an actual http request/response look like?
&lt;/h3&gt;

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

&lt;p&gt;HTTP has evolved through three major versions, each solving critical performance bottlenecks that became apparent as the web grew. Understanding this evolution isn't just history it's understanding the performance characteristics and limitations of the systems you're building today.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP/1.1 (1997) - The Foundation
&lt;/h3&gt;

&lt;p&gt;HTTP/1.1 was the protocol that took the web mainstream. It introduced &lt;strong&gt;persistent connections&lt;/strong&gt; (keep-alive), which meant you could send multiple requests over a single TCP connection instead of opening a new connection for every request. This was huge establishing a TCP connection involves a three-way handshake that takes at least one round-trip time, and with the old HTTP/1.0 model, a page with 50 resources meant 50 TCP handshakes. That's a lot of wasted time and bandwidth.&lt;/p&gt;

&lt;p&gt;With persistent connections, you connect once and reuse that connection:&lt;/p&gt;

&lt;h3&gt;
  
  
  TCP 3 way handshake
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connect (TCP handshake: 50-100ms)
Request 1 → Response 1
Request 2 → Response 2  
Request 3 → Response 3
[... many more requests ...]
Disconnect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTTP/1.1 also gave us &lt;strong&gt;chunked transfer encoding&lt;/strong&gt;, which lets servers start sending data before they know the total size. This is critical for streaming use cases imagine trying to stream a video if you had to buffer the entire file first to calculate Content-Length. Chunked encoding solved this by letting the server send data in pieces with each piece prefixed by its size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But HTTP/1.1 had a fatal flaw&lt;/strong&gt;: head-of-line blocking. Requests were still processed sequentially over each connection. Even though you had persistent connections, you couldn't truly parallelize requests. If Request 1 took 5 seconds, Request 2 had to wait those full 5 seconds before it could even start. Browsers worked around this by opening multiple connections (typically 6 per domain), but this was a hack, not a solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP/2 (2015) - The Performance Revolution
&lt;/h3&gt;

&lt;p&gt;HTTP/2 fundamentally changed how data flows over a connection with &lt;strong&gt;multiplexing&lt;/strong&gt; the ability to send multiple requests and receive multiple responses simultaneously over a single connection. Instead of requests waiting in line, they all fly at once:&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────┐
│   Single TCP Connection          │
├──────────────────────────────────┤
│ Stream 1: GET /style.css     ───▶│
│ Stream 2: GET /script.js     ───▶│
│ Stream 3: GET /image.png     ───▶│
│ Stream 1: 200 OK [CSS data]  ◀───│
│ Stream 3: 200 OK [IMG data]  ◀───│ (came back first!)
│ Stream 2: 200 OK [JS data]   ◀───│
└──────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how responses can come back out of order Stream 3 finishes before Stream 2, and that's fine. No more head-of-line blocking at the HTTP layer. This change alone typically improves page load times by 30-50%.&lt;/p&gt;

&lt;p&gt;HTTP/2 also introduced &lt;strong&gt;header compression&lt;/strong&gt; using HPACK. HTTP/1.1 sent the same headers repeatedly with every request, wasting kilobytes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/api/users/1&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.example.com&lt;/span&gt;
&lt;span class="na"&gt;User-Agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36...&lt;/span&gt;
&lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&lt;/span&gt;
&lt;span class="na"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="na"&gt;Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;session=abc123; prefs=dark_mode; ...&lt;/span&gt;

GET /api/users/2 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36...
[... exact same headers repeated ...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTTP/2 compresses these headers and remembers them across requests, so subsequent requests only send the differences. This saves significant bandwidth, especially for APIs where you make many requests with identical headers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The catch&lt;/strong&gt;: HTTP/2 still runs over TCP, and TCP has its own head-of-line blocking at the packet level. If a single TCP packet is lost, everything behind it stalls while that packet is retransmitted even unrelated streams. This is especially painful on mobile networks with packet loss.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP/3 (2022) - Breaking Free from TCP
&lt;/h3&gt;

&lt;p&gt;HTTP/3 made the radical decision to abandon TCP entirely and use &lt;strong&gt;QUIC over UDP&lt;/strong&gt; instead. This sounds crazy UDP is the "unreliable" protocol, right? But QUIC implements reliability features on top of UDP while fixing TCP's fundamental limitations.&lt;/p&gt;

&lt;p&gt;The key innovation is &lt;strong&gt;per-stream head-of-line blocking&lt;/strong&gt;. In HTTP/2, a lost packet blocks all streams. In HTTP/3, a lost packet only blocks the stream it belongs to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stream 1: [Packet 1] [LOST!] [Packet 3] → Stalls waiting for Packet 2
Stream 2: [Packet 1] [Packet 2] [Packet 3] → Keeps flowing!
Stream 3: [Packet 1] [Packet 2] → Keeps flowing!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is massive for mobile users. On spotty connections with 5% packet loss, HTTP/3 can be dramatically faster than HTTP/2 because lost packets don't stall unrelated requests.&lt;/p&gt;

&lt;p&gt;HTTP/3 also has &lt;strong&gt;built-in encryption&lt;/strong&gt; with TLS 1.3 integrated into QUIC. There's no separate TLS handshake it's all one negotiation. Even better, HTTP/3 supports &lt;strong&gt;0-RTT resumption&lt;/strong&gt;, meaning if you've connected before, your first request can include data immediately without waiting for handshakes. This is perfect for mobile apps that frequently reconnect.&lt;/p&gt;

&lt;p&gt;Finally, HTTP/3 has &lt;strong&gt;connection migration&lt;/strong&gt;. When your phone switches from WiFi to cellular, TCP connections die and need to be reestablished. QUIC connections use connection IDs instead of IP addresses, so the connection seamlessly migrates to the new network. Your video keeps streaming, your API calls keep flowing no interruption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Current reality&lt;/strong&gt;: HTTP/3 is used by Google (all properties), Facebook, Cloudflare, and other major services. Browser support is universal. But server adoption is still growing because it requires new infrastructure. Most applications still run on HTTP/1.1 or HTTP/2, and that's fine they work well. HTTP/3 is an optimization, not a requirement.&lt;/p&gt;

&lt;h3&gt;
  
  
  What This Means for You
&lt;/h3&gt;

&lt;p&gt;Here's the practical takeaway: &lt;strong&gt;you usually don't choose the HTTP version&lt;/strong&gt; your hosting provider, CDN, or load balancer handles it. Your application code doesn't change between versions. The same Express/Flask/Spring Boot code works with all versions.&lt;/p&gt;

&lt;p&gt;What matters is understanding that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP/1.1 is sequential (slow with many requests)&lt;/li&gt;
&lt;li&gt;HTTP/2 is parallel (fast with many requests)
&lt;/li&gt;
&lt;li&gt;HTTP/3 is resilient (fast even on bad networks)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When debugging performance issues, check which version is being used. If you're on HTTP/1.1 and making 100 requests to load a page, upgrading to HTTP/2 might be your biggest performance win. If your mobile users complain about slow connections, HTTP/3 might help. But if you're making 5 API calls and they're already fast, the version doesn't matter much.&lt;/p&gt;




&lt;h2&gt;
  
  
  HTTP Messages
&lt;/h2&gt;

&lt;p&gt;Every HTTP interaction uses this format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐
│ Start Line   │ ← Method + Path or Status
├──────────────┤
│ Headers      │ ← Metadata
│ Header: value│
├──────────────┤
│ (blank line) │ ← Required separator
├──────────────┤
│ Body         │ ← Optional data
└──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Request Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/api/users&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.example.com&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="na"&gt;Content-Length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;27&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parts:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Request line&lt;/strong&gt;: &lt;code&gt;POST /api/users HTTP/1.1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers&lt;/strong&gt;: Host, Content-Type, Content-Length&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blank line&lt;/strong&gt;: Required!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Body&lt;/strong&gt;: JSON data&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Response Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;201&lt;/span&gt; &lt;span class="ne"&gt;Created&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api/users/123&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parts:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Status line&lt;/strong&gt;: &lt;code&gt;HTTP/1.1 201 Created&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headers&lt;/strong&gt;: Content-Type, Location&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blank line&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Body&lt;/strong&gt;: Created resource&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  HTTP Headers
&lt;/h2&gt;

&lt;p&gt;Headers are key-value pairs that provide metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  Critical Request Headers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Host&lt;/strong&gt; (required)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Host: api.example.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which server to route to&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authorization&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Authorization: Bearer eyJhbGc...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authentication credentials&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content-Type&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Type: application/json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Format of request body&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accept&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Accept: application/json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What response formats you'll accept&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cookie&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cookie: session_id=abc123
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send stored cookies&lt;/p&gt;

&lt;h3&gt;
  
  
  Critical Response Headers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Content-Type&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Type: application/json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Format of response body&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set-Cookie&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session_id=abc123; HttpOnly; Secure
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store cookie on client&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache-Control&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: public, max-age=3600
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caching instructions&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Location: /api/users/123
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redirect or created resource URL&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Headers (Must-Have)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Strict-Transport-Security&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Strict-Transport-Security: max-age=31536000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Force HTTPS&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content-Security-Policy&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Security-Policy: default-src 'self'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prevent XSS attacks&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;X-Content-Type-Options&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;X-Content-Type-Options: nosniff
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prevent MIME sniffing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;X-Frame-Options&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;X-Frame-Options: DENY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prevent clickjacking&lt;/p&gt;

&lt;h3&gt;
  
  
  Cookie Attributes (Security)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Set-Cookie: session=abc; HttpOnly; Secure; SameSite=Strict
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HttpOnly&lt;/strong&gt;: JavaScript can't access (prevents XSS)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure&lt;/strong&gt;: HTTPS only (prevents MITM)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SameSite=Strict&lt;/strong&gt;: Blocks CSRF attacks&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  HTTP Headers, Reference Table
&lt;/h2&gt;

&lt;p&gt;Headers provide metadata and control behavior.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Header&lt;/th&gt;
&lt;th&gt;Explanation&lt;/th&gt;
&lt;th&gt;Common Values&lt;/th&gt;
&lt;th&gt;Usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Host&lt;/td&gt;
&lt;td&gt;Target server&lt;/td&gt;
&lt;td&gt;&lt;code&gt;api.example.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization&lt;/td&gt;
&lt;td&gt;Credentials&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Bearer &amp;lt;token&amp;gt;&lt;/code&gt;, &lt;code&gt;Basic &amp;lt;base64&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Type&lt;/td&gt;
&lt;td&gt;Body format&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;application/json&lt;/code&gt;, &lt;code&gt;text/html&lt;/code&gt;, &lt;code&gt;multipart/form-data&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Parsing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accept&lt;/td&gt;
&lt;td&gt;Desired response&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;application/json&lt;/code&gt;, &lt;code&gt;text/html&lt;/code&gt;, &lt;code&gt;*/*&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Content negotiation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accept-Language&lt;/td&gt;
&lt;td&gt;Preferred language&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;en-US&lt;/code&gt;, &lt;code&gt;fr-FR&lt;/code&gt;, &lt;code&gt;hi-IN&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Localization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User-Agent&lt;/td&gt;
&lt;td&gt;Client info&lt;/td&gt;
&lt;td&gt;Browser, curl, Postman&lt;/td&gt;
&lt;td&gt;Analytics, debugging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cookie&lt;/td&gt;
&lt;td&gt;Client state&lt;/td&gt;
&lt;td&gt;&lt;code&gt;session_id=abc123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set-Cookie&lt;/td&gt;
&lt;td&gt;Store cookie&lt;/td&gt;
&lt;td&gt;&lt;code&gt;HttpOnly; Secure; SameSite=Strict&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-Control&lt;/td&gt;
&lt;td&gt;Caching&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;no-cache&lt;/code&gt;, &lt;code&gt;max-age=3600&lt;/code&gt;, &lt;code&gt;public&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Location&lt;/td&gt;
&lt;td&gt;Redirect or new resource&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/users/123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Navigation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strict-Transport-Security&lt;/td&gt;
&lt;td&gt;Force HTTPS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;max-age=31536000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Security-Policy&lt;/td&gt;
&lt;td&gt;Prevent XSS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;default-src 'self'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Content-Type-Options&lt;/td&gt;
&lt;td&gt;Prevent MIME sniffing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nosniff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Frame-Options&lt;/td&gt;
&lt;td&gt;Clickjacking protection&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;DENY&lt;/code&gt;, &lt;code&gt;SAMEORIGIN&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transfer-Encoding&lt;/td&gt;
&lt;td&gt;Body transfer&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;chunked&lt;/code&gt;, &lt;code&gt;gzip&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Streaming/Compression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connection&lt;/td&gt;
&lt;td&gt;Connection persistence&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;keep-alive&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access-Control-Allow-Origin&lt;/td&gt;
&lt;td&gt;CORS origin&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;*&lt;/code&gt;, &lt;code&gt;https://example.com&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Cross-origin requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access-Control-Allow-Methods&lt;/td&gt;
&lt;td&gt;Allowed HTTP methods&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET, POST, PUT, DELETE, OPTIONS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CORS control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access-Control-Allow-Headers&lt;/td&gt;
&lt;td&gt;Allowed headers in CORS&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Authorization, Content-Type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CORS control&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  HTTP Methods
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Safe&lt;/th&gt;
&lt;th&gt;Idempotent&lt;/th&gt;
&lt;th&gt;Body&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;Retrieve resource&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;POST&lt;/td&gt;
&lt;td&gt;Create resource&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;PUT&lt;/td&gt;
&lt;td&gt;Replace resource&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;PATCH&lt;/td&gt;
&lt;td&gt;Update resource&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;DELETE&lt;/td&gt;
&lt;td&gt;Remove resource&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;OPTIONS&lt;/td&gt;
&lt;td&gt;Check capabilities&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;
  
  
  Status Codes
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;### you are not supposed to remember all.&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4m187klyicndkdddsfy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4m187klyicndkdddsfy.webp" alt=" " width="800" height="1017"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Mostly used Codes.
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;When to Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;OK&lt;/td&gt;
&lt;td&gt;Standard success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;201&lt;/td&gt;
&lt;td&gt;Created&lt;/td&gt;
&lt;td&gt;Resource created&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;204&lt;/td&gt;
&lt;td&gt;No Content&lt;/td&gt;
&lt;td&gt;Success without body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;301&lt;/td&gt;
&lt;td&gt;Moved Permanently&lt;/td&gt;
&lt;td&gt;Permanent redirect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;304&lt;/td&gt;
&lt;td&gt;Not Modified&lt;/td&gt;
&lt;td&gt;Use cached resource&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;Bad Request&lt;/td&gt;
&lt;td&gt;Invalid input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;Unauthorized&lt;/td&gt;
&lt;td&gt;Auth required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;403&lt;/td&gt;
&lt;td&gt;Forbidden&lt;/td&gt;
&lt;td&gt;No permission&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;404&lt;/td&gt;
&lt;td&gt;Not Found&lt;/td&gt;
&lt;td&gt;Resource missing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;429&lt;/td&gt;
&lt;td&gt;Too Many Requests&lt;/td&gt;
&lt;td&gt;Rate limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;Internal Server Error&lt;/td&gt;
&lt;td&gt;Server issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;502&lt;/td&gt;
&lt;td&gt;Bad Gateway&lt;/td&gt;
&lt;td&gt;Upstream issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;503&lt;/td&gt;
&lt;td&gt;Service Unavailable&lt;/td&gt;
&lt;td&gt;Temporary downtime&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  CORS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CORS (Cross-Origin Resource Sharing)&lt;/strong&gt;: Browser security that blocks cross-origin requests by default.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// You're on https://frontend.com&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.backend.com/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// ❌ Blocked by browser!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;Server sends CORS headers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Simple vs Preflight Requests
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Simple request&lt;/strong&gt; (no preflight):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /api/data
Origin: https://frontend.com

Response:
Access-Control-Allow-Origin: https://frontend.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Preflight request&lt;/strong&gt; (checks first):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;OPTIONS /api/data
Origin: https://frontend.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

Response:
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400

Then actual POST request proceeds...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Triggers preflight:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Methods: PUT, DELETE, PATCH&lt;/li&gt;
&lt;li&gt;Custom headers&lt;/li&gt;
&lt;li&gt;Content-Type: application/json&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  Common CORS Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Node.js/Express&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Origin&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="s1"&gt;https://frontend.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Methods&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="s1"&gt;GET,POST,PUT,DELETE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Headers&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="s1"&gt;Content-Type,Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Credentials&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="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OPTIONS&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;next&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;
  
  
  Caching
&lt;/h2&gt;

&lt;p&gt;Caching saves bandwidth and improves speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache-Control Header
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Don't cache (sensitive data):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: private, no-store
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cache for 1 hour:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: public, max-age=3600
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cache but revalidate:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: public, max-age=0, must-revalidate
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cache forever (static assets):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Cache-Control: public, max-age=31536000, immutable
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ETag (Smart Caching)
&lt;/h3&gt;

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

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

200 OK
ETag: "abc123"
{"id":123,"name":"Alice"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /api/users/123
If-None-Match: "abc123"

304 Not Modified
(no body - use cache)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;If data changed:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;200 OK
ETag: "xyz789"
{"id":123,"name":"Alice Updated"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h3&gt;
  
  
  Cache Strategy by Content Type
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;# HTML pages
Cache-Control: public, max-age=0, must-revalidate

# API responses
Cache-Control: private, no-cache

# Static assets (CSS, JS, images with hash in filename)
Cache-Control: public, max-age=31536000, immutable

# User-specific data
Cache-Control: private, max-age=300

# Sensitive data
Cache-Control: private, no-store
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Content Negotiation
&lt;/h2&gt;

&lt;p&gt;Client and server agree on format/language.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accept Header
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /api/users
Accept: application/json

Response:
Content-Type: application/json
{"users":[...]}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /page
Accept: text/html

Response:
Content-Type: text/html
&amp;lt;html&amp;gt;...&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Accept-Language
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Accept-Language: es-MX, es;q=0.9, en;q=0.8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Translation: "I prefer Mexican Spanish, any Spanish is fine, English as backup"&lt;/p&gt;

&lt;h3&gt;
  
  
  Quality Values (q)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Accept: application/json, application/xml;q=0.9, */*;q=0.8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;q=1.0&lt;/code&gt; (default): Preferred&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;q=0.9&lt;/code&gt;: Less preferred&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;q=0.8&lt;/code&gt;: Least preferred&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Compression
&lt;/h2&gt;

&lt;p&gt;Compression reduces payload size significantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accept-Encoding
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /api/data
Accept-Encoding: gzip, br

Response:
Content-Encoding: gzip
[compressed data]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Compression Algorithms
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;gzip&lt;/strong&gt; (universal support)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Encoding: gzip
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Brotli&lt;/strong&gt; (better compression, modern browsers)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Encoding: br
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real Impact
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Original: 1.2 MB
Gzipped:  300 KB
Savings:  75%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Always compress:&lt;/strong&gt; Text, JSON, HTML, CSS, JavaScript&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Don't compress:&lt;/strong&gt; Images (already compressed), videos&lt;/p&gt;


&lt;h2&gt;
  
  
  Persistent Connections
&lt;/h2&gt;

&lt;p&gt;Keep connections open for multiple requests.&lt;/p&gt;
&lt;h3&gt;
  
  
  HTTP/1.1 Keep-Alive
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Connection: keep-alive
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────┐
│ Connect once                     │
│ Request 1 → Response 1           │
│ Request 2 → Response 2           │
│ Request 3 → Response 3           │
│ Disconnect                       │
└─────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;vs Old way:&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;Connect → Request 1 → Response 1 → Disconnect
Connect → Request 2 → Response 2 → Disconnect
Connect → Request 3 → Response 3 → Disconnect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Eliminates TCP handshake overhead (50-100ms per connection)&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP/2 &amp;amp; HTTP/3
&lt;/h3&gt;

&lt;p&gt;Persistent connections built-in. No special headers needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Streaming
&lt;/h2&gt;

&lt;p&gt;Send data without knowing total size.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chunked Transfer Encoding
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Transfer-Encoding: chunked

1a\r\n
This is the first chunk\r\n
14\r\n
This is the second\r\n
0\r\n
\r\n
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each chunk: size in hex + &lt;code&gt;\r\n&lt;/code&gt; + data + &lt;code&gt;\r\n&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Last chunk: &lt;code&gt;0\r\n\r\n&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Real-World Uses
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Streaming API responses:&lt;/strong&gt;&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;// Server-sent events&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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="s1"&gt;text/event-stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transfer-Encoding&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="s1"&gt;chunked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`data: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()})}&lt;/span&gt;&lt;span class="s2"&gt;\n\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Streaming logs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.example.com/logs/stream
&lt;span class="c"&gt;# Receives log lines as they're generated&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Video streaming:&lt;/strong&gt;&lt;br&gt;
Sends chunks as they're encoded/available&lt;/p&gt;


&lt;h2&gt;
  
  
  HTTPS
&lt;/h2&gt;

&lt;p&gt;HTTPS = HTTP + TLS encryption&lt;/p&gt;
&lt;h3&gt;
  
  
  Why HTTPS?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Without HTTPS:&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;You → "password123" → [Anyone listening] → Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;With HTTPS:&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;You → [encrypted gibberish] → Server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if intercepted, data is unreadable.&lt;/p&gt;

&lt;h3&gt;
  
  
  What HTTPS Provides
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Encryption&lt;/strong&gt;: Data can't be read&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt;: Server is who they claim&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrity&lt;/strong&gt;: Data can't be modified&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  TLS Handshake (Simplified)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → Server: "Let's use HTTPS"
Server → Client: "Here's my certificate"
Client verifies certificate
Client → Server: [Encrypted session key]
Both use session key for encryption
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h3&gt;
  
  
  Certificate Verification
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Browser checks:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Certificate not expired?&lt;/li&gt;
&lt;li&gt;Issued by trusted CA?&lt;/li&gt;
&lt;li&gt;Domain matches?&lt;/li&gt;
&lt;li&gt;Not revoked?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If all pass: 🔒 Green lock&lt;br&gt;&lt;br&gt;
If fail: ⚠️ Security warning&lt;/p&gt;
&lt;h3&gt;
  
  
  HTTP → HTTPS Upgrade
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Force HTTPS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;301&lt;/span&gt; &lt;span class="ne"&gt;Moved Permanently&lt;/span&gt;
&lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://example.com&lt;/span&gt;
&lt;span class="na"&gt;Strict-Transport-Security&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;max-age=31536000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HSTS (HTTP Strict Transport Security):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Strict-Transport-Security: max-age=31536000; includeSubDomains
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browser automatically uses HTTPS for all requests to this domain.&lt;/p&gt;




&lt;h2&gt;
  
  
  Debugging HTTP
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Browser DevTools
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;F12 → Network Tab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All requests/responses&lt;/li&gt;
&lt;li&gt;Headers&lt;/li&gt;
&lt;li&gt;Timing&lt;/li&gt;
&lt;li&gt;Payload size&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  cURL (Command Line)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Basic request&lt;/span&gt;
curl https://api.example.com/users

&lt;span class="c"&gt;# Show headers&lt;/span&gt;
curl &lt;span class="nt"&gt;-v&lt;/span&gt; https://api.example.com/users

&lt;span class="c"&gt;# POST with data&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.example.com/users &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"Alice"}'&lt;/span&gt;

&lt;span class="c"&gt;# Follow redirects&lt;/span&gt;
curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://example.com

&lt;span class="c"&gt;# Save response&lt;/span&gt;
curl &lt;span class="nt"&gt;-o&lt;/span&gt; output.json https://api.example.com/data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Common Issues
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CORS errors:&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;Check: Access-Control-Allow-Origin header
Fix: Add header on server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;401 Unauthorized:&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;Check: Authorization header present and valid
Fix: Include valid token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;304 Not Modified confusion:&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;Remember: 304 means use cached version (not an error!)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Unexpected status codes:&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;Check: What server is actually returning
Use: curl -v to see full response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Essential Headers Cheat Sheet
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Host: api.example.com              (required)
Authorization: Bearer &amp;lt;token&amp;gt;       (auth)
Content-Type: application/json      (body format)
Accept: application/json            (wanted format)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Type: application/json      (body format)
Cache-Control: max-age=3600         (caching)
Access-Control-Allow-Origin: *      (CORS)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Strict-Transport-Security: max-age=31536000
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices Summary
&lt;/h2&gt;

&lt;h3&gt;
  
  
  API Design
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use appropriate HTTP methods&lt;/li&gt;
&lt;li&gt;Return meaningful status codes&lt;/li&gt;
&lt;li&gt;Include proper headers (Content-Type, etc.)&lt;/li&gt;
&lt;li&gt;Implement caching where appropriate&lt;/li&gt;
&lt;li&gt;Version your API (URL or header)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Always use HTTPS in production&lt;/li&gt;
&lt;li&gt;Set security headers (HSTS, CSP, etc.)&lt;/li&gt;
&lt;li&gt;Use HttpOnly, Secure cookies&lt;/li&gt;
&lt;li&gt;Implement rate limiting&lt;/li&gt;
&lt;li&gt;Validate all inputs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Enable compression (gzip/brotli)&lt;/li&gt;
&lt;li&gt;Use appropriate caching headers&lt;/li&gt;
&lt;li&gt;Leverage HTTP/2 if available&lt;/li&gt;
&lt;li&gt;Minimize payload size&lt;/li&gt;
&lt;li&gt;Use persistent connections&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Debugging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Check Network tab first&lt;/li&gt;
&lt;li&gt;Use curl for API testing&lt;/li&gt;
&lt;li&gt;Include request IDs for tracing&lt;/li&gt;
&lt;li&gt;Log headers in development&lt;/li&gt;
&lt;li&gt;Test with real network conditions&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt; HTTP is simple at its core requests and responses with headers and bodies. Everything else is optimization and security built on top of that foundation.&lt;/p&gt;

&lt;p&gt;Master these fundamentals, and you'll understand what's happening in any HTTP-based system.&lt;/p&gt;

&lt;h1&gt;
  
  
  The End
&lt;/h1&gt;

&lt;p&gt;Thank you for reading. Hope you don't need anything else to learn http.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>programming</category>
      <category>architecture</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
