<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Priyanshu's Blog]]></title><description><![CDATA[Priyanshu's Blog]]></description><link>https://blog.priyanshumaitra.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 24 Apr 2026 16:25:16 GMT</lastBuildDate><atom:link href="https://blog.priyanshumaitra.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Getting Started with cURL]]></title><description><![CDATA[In second year, a senior showed me something that felt like a superpower at the time. He opened his terminal, typed one line, and got back a full JSON response from a live API. No Postman. No browser. No code. Just the terminal.
I asked him what that...]]></description><link>https://blog.priyanshumaitra.dev/getting-started-with-curl</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/getting-started-with-curl</guid><category><![CDATA[networtmin]]></category><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[computer networking]]></category><category><![CDATA[curl]]></category><category><![CDATA[curl-command]]></category><category><![CDATA[cURL for beginner]]></category><category><![CDATA[command line interface]]></category><category><![CDATA[command line tools]]></category><category><![CDATA[cli tool]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Sun, 01 Feb 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>In second year, a senior showed me something that felt like a superpower at the time. He opened his terminal, typed one line, and got back a full JSON response from a live API. No Postman. No browser. No code. Just the terminal.</p>
<p>I asked him what that was. He said "cURL" like it was obvious.</p>
<p>It wasn't obvious to me. I'd been building APIs for a few months and testing them by running my frontend, clicking buttons, and hoping the network tab in Chrome DevTools would show me something useful. Half the time it didn't, and I'd spend an hour not knowing whether the bug was in my frontend code or my backend.</p>
<p>That senior showed me in five minutes that I'd been doing it the hard way. This blog is the five-minute version I wish I'd had.</p>
<h2 id="heading-what-even-is-a-server">What Even is a Server?</h2>
<p>Before cURL, let's talk about what we're actually talking to.</p>
<p>When you open Instagram, your phone doesn't have your feed stored locally. It sends a request to Instagram's servers — computers sitting in a data center somewhere — asking for your latest posts. Those servers process the request, fetch your data from a database, and send it back. Your app receives it and displays it.</p>
<p>This is the client-server model. Your phone is the client. Instagram's data center is the server. They talk to each other over HTTP — the same protocol your browser uses.</p>
<p>Here's the thing: your browser is a client. Postman is a client. Your mobile app is a client. And cURL? cURL is a client too — just a very stripped-down, terminal-based one.</p>
<h2 id="heading-what-is-curl">What is cURL</h2>
<p>cURL stands for Client URL. It's a command-line tool that lets you send HTTP requests to servers and see their responses. That's it.</p>
<p>No interface. No buttons. No project to set up. You type a command, you get a response. Done.</p>
<p>Programmers use cURL to:</p>
<ul>
<li>Test APIs they've built before writing frontend code</li>
<li>Debug why a server is returning a certain response</li>
<li>Check if an endpoint is even reachable</li>
<li>Quickly inspect what a public API returns</li>
<li>Automate HTTP requests in shell scripts</li>
</ul>
<p>The reason it's worth learning isn't that it replaces Postman or your code. It's that it removes every layer between you and the server. No middleware, no framework, no library. Just your request and whatever comes back.</p>
<p>When something breaks and you don't know if it's your frontend, your backend, or the API you're calling — cURL isolates the answer immediately.</p>
<h2 id="heading-your-first-curl-command">Your First cURL Command</h2>
<p>Open your terminal. Type this:</p>
<pre><code class="lang-bash">curl https://httpbin.org/get
</code></pre>
<p>That's it. Press Enter.</p>
<p>You'll get back something like:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"args"</span>: {},
  <span class="hljs-attr">"headers"</span>: {
    <span class="hljs-attr">"Accept"</span>: <span class="hljs-string">"*/*"</span>,
    <span class="hljs-attr">"Host"</span>: <span class="hljs-string">"httpbin.org"</span>,
    <span class="hljs-attr">"User-Agent"</span>: <span class="hljs-string">"curl/7.88.1"</span>
  },
  <span class="hljs-attr">"origin"</span>: <span class="hljs-string">"49.206.12.87"</span>,
  <span class="hljs-attr">"url"</span>: <span class="hljs-string">"https://httpbin.org/get"</span>
}
</code></pre>
<p>You just made an HTTP GET request to a real server and got a real response. <code>httpbin.org</code> is a free service built specifically for testing HTTP requests — it echoes back information about the request you sent.</p>
<p>Look at what it returned:</p>
<ul>
<li><code>headers</code>: The metadata your request carried — including <code>User-Agent</code> which shows you sent this as "curl" version whatever</li>
<li><code>origin</code>: Your public IP address</li>
<li><code>url</code>: The exact URL you requested</li>
</ul>
<p>You didn't write any code. You didn't open a browser. You sent a network request from your terminal and read the response.</p>
<h2 id="heading-understanding-the-response">Understanding the Response</h2>
<p>Let's slow down and understand what's happening when you make a request.</p>
<p>Every HTTP interaction has two parts: a <strong>request</strong> (what you send) and a <strong>response</strong> (what comes back).</p>
<p><strong>The request</strong> has:</p>
<ul>
<li>A method — GET, POST, PUT, DELETE, etc. GET means "give me data." POST means "here's data, process it."</li>
<li>A URL — where you're sending it</li>
<li>Headers — metadata about the request (what format you accept, authentication tokens, etc.)</li>
<li>A body — only relevant for POST and PUT requests, this is the actual data you're sending</li>
</ul>
<p><strong>The response</strong> has:</p>
<ul>
<li>A status code — a three-digit number that tells you what happened</li>
<li>Headers — metadata about the response</li>
<li>A body — the actual data returned, usually HTML or JSON</li>
</ul>
<p>Status codes are the shorthand of HTTP. The ones you'll see constantly:</p>
<ul>
<li><code>200 OK</code> — worked perfectly</li>
<li><code>201 Created</code> — your POST request created something</li>
<li><code>400 Bad Request</code> — you sent something malformed</li>
<li><code>401 Unauthorized</code> — you need to authenticate</li>
<li><code>404 Not Found</code> — that resource doesn't exist</li>
<li><code>500 Internal Server Error</code> — the server broke, not you</li>
</ul>
<p>To see the status code and response headers with cURL, add the <code>-i</code> flag:</p>
<pre><code class="lang-bash">curl -i https://httpbin.org/get
</code></pre>
<p>Now you'll see the full response, headers first:</p>
<pre><code>HTTP/<span class="hljs-number">2</span> <span class="hljs-number">200</span>
content-type: application/json
...

{
  <span class="hljs-string">"args"</span>: {},
  ...
}
</code></pre><p>That first line — <code>HTTP/2 200</code> — is the status code. 200 means success. Any time you're debugging and not sure if your request is even landing correctly, <code>-i</code> tells you immediately.</p>
<h2 id="heading-making-a-get-request-to-a-real-api">Making a GET Request to a Real API</h2>
<p>GET requests are the simplest — you're asking for data, not sending any. Let's try a real public API.</p>
<pre><code class="lang-bash">curl https://api.github.com/users/torvalds
</code></pre>
<p>This fetches Linus Torvalds' GitHub profile via the GitHub API. You'll get back a JSON object with his username, follower count, public repository count, and more:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"login"</span>: <span class="hljs-string">"torvalds"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Linus Torvalds"</span>,
  <span class="hljs-attr">"public_repos"</span>: <span class="hljs-number">8</span>,
  <span class="hljs-attr">"followers"</span>: <span class="hljs-number">240000</span>,
  ...
}
</code></pre>
<p>No authentication, no setup. Just a GET request to a public endpoint. This is how you'd test any public API — skip Postman for a moment and just curl it.</p>
<p>If the JSON response is one long unreadable line, pipe it through <code>python3 -m json.tool</code> for pretty printing:</p>
<pre><code class="lang-bash">curl https://api.github.com/users/torvalds | python3 -m json.tool
</code></pre>
<p>Now it formats nicely with indentation.</p>
<h2 id="heading-making-a-post-request">Making a POST Request</h2>
<p>POST is where things get interesting. GET fetches data. POST sends data.</p>
<p>When you submit a login form, fill out a survey, or create a new record via an API — that's POST. You're sending a body of data to the server and asking it to do something with it.</p>
<p>Here's how a POST request looks in cURL:</p>
<pre><code class="lang-bash">curl -X POST https://httpbin.org/post \
  -H <span class="hljs-string">"Content-Type: application/json"</span> \
  -d <span class="hljs-string">'{"name": "Priyanshu", "role": "developer"}'</span>
</code></pre>
<p>Let's break down what's new here:</p>
<p><code>-X POST</code> tells cURL to use the POST method instead of GET (which is the default).</p>
<p><code>-H "Content-Type: application/json"</code> adds a header. This tells the server: "The data I'm sending is JSON." Servers use this to know how to parse your body. If you send JSON without this header, many servers will reject it or misread it.</p>
<p><code>-d '{"name": "Priyanshu", "role": "developer"}'</code> is the body — the actual data you're sending. The <code>-d</code> flag means "data".</p>
<p>The server at <code>httpbin.org/post</code> echoes back what you sent:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"data"</span>: <span class="hljs-string">"{\"name\": \"Priyanshu\", \"role\": \"developer\"}"</span>,
  <span class="hljs-attr">"headers"</span>: {
    <span class="hljs-attr">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
    ...
  },
  <span class="hljs-attr">"json"</span>: {
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Priyanshu"</span>,
    <span class="hljs-attr">"role"</span>: <span class="hljs-string">"developer"</span>
  },
  ...
}
</code></pre>
<p>Your data arrived. The server parsed it as JSON. This is exactly what happens when your frontend sends data to your backend — cURL just makes the same thing happen from your terminal.</p>
<h2 id="heading-using-curl-to-talk-to-your-own-api">Using cURL to Talk to Your Own API</h2>
<p>The real power of cURL for most developers is testing their own endpoints before writing frontend code.</p>
<p>Say you've built a simple Express server running locally:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># GET your data</span>
curl http://localhost:3000/api/users

<span class="hljs-comment"># POST new data</span>
curl -X POST http://localhost:3000/api/users \
  -H <span class="hljs-string">"Content-Type: application/json"</span> \
  -d <span class="hljs-string">'{"name": "Test User", "email": "test@example.com"}'</span>
</code></pre>
<p>Before writing a single line of React or any frontend code, you can verify your backend is working exactly as expected. The response tells you immediately: is the route registered? Is the data being parsed? Is the database connection working?</p>
<p>If the curl works and the frontend doesn't, the bug is in the frontend. If curl doesn't work either, the bug is in the backend. That isolation saves hours.</p>
<p>For endpoints that need authentication, pass the token in a header:</p>
<pre><code class="lang-bash">curl http://localhost:3000/api/profile \
  -H <span class="hljs-string">"Authorization: Bearer your_token_here"</span>
</code></pre>
<h2 id="heading-common-mistakes-beginners-make">Common Mistakes Beginners Make</h2>
<p><strong>Forgetting the Content-Type header on POST requests.</strong>
If you send JSON data without <code>-H "Content-Type: application/json"</code>, many servers won't parse the body correctly. You'll get confusing errors that look like the data isn't arriving. It is arriving — the server just doesn't know how to read it.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Wrong - no Content-Type</span>
curl -X POST http://localhost:3000/api/users \
  -d <span class="hljs-string">'{"name": "Test"}'</span>

<span class="hljs-comment"># Correct</span>
curl -X POST http://localhost:3000/api/users \
  -H <span class="hljs-string">"Content-Type: application/json"</span> \
  -d <span class="hljs-string">'{"name": "Test"}'</span>
</code></pre>
<p><strong>Using single quotes on Windows.</strong>
The examples in this blog use single quotes around JSON, which works perfectly on Linux and macOS. On Windows Command Prompt, single quotes aren't string delimiters — you need double quotes, and the inner quotes need escaping:</p>
<pre><code class="lang-bash">curl -X POST http://localhost:3000/api/users -H <span class="hljs-string">"Content-Type: application/json"</span> -d <span class="hljs-string">"{\"name\": \"Test\"}"</span>
</code></pre>
<p>Windows PowerShell handles this differently again. If you're on Windows and running into quote errors, this is almost certainly why.</p>
<p><strong>Not checking the status code.</strong>
A request can "complete" in cURL and still have failed at the HTTP level. If you get back a 401 or 404 response, cURL by default exits with status 0 (success) because the request itself completed — it's just the server said no. Use <code>-i</code> to always see the status code in your response.</p>
<p><strong>Curling HTTPS URLs with certificate issues.</strong>
Sometimes you'll hit a self-signed certificate on a development server and cURL refuses to connect. The temptation is to add <code>-k</code> (insecure) to bypass certificate verification. That's fine locally during development. Never do it in production scripts or with real credentials.</p>
<p><strong>Assuming GET when you mean POST.</strong>
cURL defaults to GET. If you forget <code>-X POST</code> on a POST request, you'll make a GET request to the same URL and get a confusing response that has nothing to do with your intended action.</p>
<h2 id="heading-the-four-flags-youll-use-90-of-the-time">The Four Flags You'll Use 90% of the Time</h2>
<p>Most day-to-day cURL usage is some combination of these:</p>
<pre><code class="lang-bash">curl https://api.example.com/endpoint          <span class="hljs-comment"># Simple GET</span>
curl -i https://api.example.com/endpoint       <span class="hljs-comment"># GET with response headers</span>
curl -X POST https://api.example.com/endpoint \
  -H <span class="hljs-string">"Content-Type: application/json"</span> \
  -d <span class="hljs-string">'{"key": "value"}'</span>                        <span class="hljs-comment"># POST with JSON body</span>
curl -H <span class="hljs-string">"Authorization: Bearer token"</span> \
  https://api.example.com/endpoint             <span class="hljs-comment"># Authenticated GET</span>
</code></pre>
<p>That's it. You don't need to memorise the entire cURL manual. These four patterns cover almost everything you'll need when building and debugging web applications.</p>
<h2 id="heading-where-to-go-from-here">Where to Go From Here</h2>
<p>Once you're comfortable with GET and POST, cURL has a lot more to offer — file uploads, cookies, following redirects, saving responses to files, verbose mode to see the full request and response headers. But none of that matters until you're fluent with the basics.</p>
<p>The best way to get there is to replace Postman with cURL for a week whenever you're testing your own APIs. You'll get fast at it quickly, and you'll start to read HTTP interactions more naturally — which pays off every time you're debugging.</p>
<p>The terminal is your most honest interface to the web. cURL is how you use it.</p>
<hr />
<p><em>cURL is one of those tools that feels minor until you internalise it. Then it becomes the first thing you reach for whenever something behaves unexpectedly over HTTP. Learn the four flags, use it on your own APIs, and everything else follows naturally.</em></p>
]]></content:encoded></item><item><title><![CDATA[Understanding HTML Tags and Elements]]></title><description><![CDATA[The first time I wrote HTML, I didn't think of it as programming. I was in school, messing around with a website builder, and someone showed me I could "view source" on any webpage and see the code behind it. I right-clicked on a Wikipedia page, hit ...]]></description><link>https://blog.priyanshumaitra.dev/understanding-html-tags-and-elements</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/understanding-html-tags-and-elements</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[HTML]]></category><category><![CDATA[HTML tags ]]></category><category><![CDATA[HTML CSS JAVASCRIPT]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Sun, 01 Feb 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>The first time I wrote HTML, I didn't think of it as programming. I was in school, messing around with a website builder, and someone showed me I could "view source" on any webpage and see the code behind it. I right-clicked on a Wikipedia page, hit "View Page Source", and was greeted by thousands of lines of angle brackets and words I didn't understand.</p>
<p>I closed the tab immediately.</p>
<p>A year later, I actually sat down to learn it properly. And what surprised me most was how simple the rules are. Not the entire HTML spec — that's enormous. But the core idea. The mental model behind every tag and every element. Once that clicked, reading HTML source code went from intimidating noise to something I could actually parse.</p>
<p>This blog is that mental model. If you've never written HTML before, this is where you start.</p>
<h2 id="heading-what-html-is">What HTML Is</h2>
<p>HTML stands for HyperText Markup Language. Ignore the name. Here's what it actually is.</p>
<p>Think about a physical newspaper. Before the design team adds fonts, colors, or layout — before any of that — a journalist writes the content. They mark up their article: "this is the headline", "this is the opening paragraph", "this is the pull quote", "this is the caption for the photo."</p>
<p>HTML does the same thing for webpages. It's a markup language that lets you describe the structure and meaning of content. "This is a heading", "this is a paragraph", "this is a link", "this is an image." No colors, no fonts, no animations — that's CSS's job. HTML just describes what things are.</p>
<p>Every webpage on the internet — every single one — has HTML as its foundation. When your browser loads <code>google.com</code>, it receives an HTML file, reads it top to bottom, and builds the page structure from it. CSS then styles it. JavaScript then adds interactivity. But the skeleton — the structure — is always HTML.</p>
<h2 id="heading-what-an-html-tag-is">What an HTML Tag Is</h2>
<p>An HTML tag is a label wrapped in angle brackets.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>That's a tag. The <code>p</code> inside tells the browser what kind of element this is — in this case, a paragraph. The angle brackets <code>&lt; &gt;</code> tell the browser "this is a tag, not content."</p>
<p>Tags come in pairs. An <strong>opening tag</strong> marks where something starts:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>A <strong>closing tag</strong> marks where it ends. It looks the same but has a forward slash before the name:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>Everything you write in HTML uses this pattern. You open something, put content inside, and close it.</p>
<p>Think of tags like parentheses in a sentence — they wrap around something to say "this block belongs together." The opening tag is the left parenthesis, the closing tag is the right parenthesis. Your content goes in between.</p>
<h2 id="heading-opening-tag-content-closing-tag-element">Opening Tag + Content + Closing Tag = Element</h2>
<p>Here's a distinction that confuses beginners for longer than it should: the difference between a <strong>tag</strong> and an <strong>element</strong>.</p>
<p>A <strong>tag</strong> is just the label itself — <code>&lt;p&gt;</code> or <code>&lt;/p&gt;</code>.</p>
<p>An <strong>element</strong> is the full thing — the opening tag, the content, and the closing tag together.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is a paragraph.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>Here, <code>&lt;p&gt;</code> is the opening tag. <code>&lt;/p&gt;</code> is the closing tag. <code>This is a paragraph.</code> is the content. The entire line — all three parts — is the <strong>element</strong>.</p>
<p>An analogy that helped me: a tag is like a bracket <code>[</code> or <code>]</code>. An element is like the full expression <code>[sentence goes here]</code>. The brackets alone aren't useful — they only make sense when they're wrapping something.</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Tag: just the label --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Element: the whole thing --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello, World!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
</code></pre>
<p>When someone says "add a paragraph element to the page," they mean write the full <code>&lt;p&gt;...&lt;/p&gt;</code> structure with content inside. When they say "the closing tag," they mean just the <code>&lt;/p&gt;</code> part.</p>
<p>Simple distinction. Genuinely useful once you're reading error messages or documentation that refers to one or the other specifically.</p>
<h2 id="heading-self-closing-elements-the-tags-with-no-pair">Self-Closing Elements: The Tags With No Pair</h2>
<p>Not every element has content between an opening and closing tag. Some elements don't have any content at all — they just exist and do their job.</p>
<p>These are called <strong>void elements</strong> or <strong>self-closing elements</strong>.</p>
<p>An image is a good example. The image itself is the content. There's no text to wrap:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"photo.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"A landscape photo"</span>&gt;</span>
</code></pre>
<p>No closing <code>&lt;/img&gt;</code>. The element is complete on its own.</p>
<p>A line break is another:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
</code></pre>
<p>You'll sometimes see these written with a trailing slash for XHTML compatibility:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"photo.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"A landscape photo"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
</code></pre>
<p>Both are valid in modern HTML. The important thing is knowing that these elements don't need — and shouldn't have — a separate closing tag.</p>
<p>Common void elements you'll use regularly:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>&gt;</span>      — images
<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>       — line break
<span class="hljs-tag">&lt;<span class="hljs-name">hr</span>&gt;</span>       — horizontal rule (a dividing line)
<span class="hljs-tag">&lt;<span class="hljs-name">input</span>&gt;</span>    — form input field
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span>&gt;</span>     — page metadata in the <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span>&gt;</span>     — linking external resources like CSS files
</code></pre>
<h2 id="heading-block-level-vs-inline-elements">Block-Level vs Inline Elements</h2>
<p>Here's one of the most practically useful distinctions in HTML, and one that a lot of beginner resources skip over.</p>
<p>Elements in HTML behave in one of two ways when the browser renders them:</p>
<p><strong>Block-level elements</strong> take up the full width of their container and always start on a new line. If you put two block elements next to each other in your HTML, they'll stack vertically.</p>
<p><strong>Inline elements</strong> only take up as much width as their content needs. They don't force a new line. Multiple inline elements sit next to each other horizontally.</p>
<p>Here's a concrete example. <code>&lt;p&gt;</code> is a block element. <code>&lt;strong&gt;</code> is an inline element:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>I really <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>love<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> writing HTML.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>This renders as a single paragraph where the word "love" is bold. The <code>&lt;strong&gt;</code> element doesn't break the line — it just wraps around the word inline.</p>
<p>Compare that to two block elements:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Main Heading<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>A paragraph below the heading.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>The heading and the paragraph each sit on their own line, stacked vertically — even if you wrote them on the same line in your HTML.</p>
<p>Why does this matter? Because understanding this behavior saves you from fighting the browser when you're trying to lay out a page. When something isn't sitting where you expect it, it's often because you're treating a block element like an inline element or vice versa.</p>
<p>Common <strong>block-level</strong> elements:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>     — generic container
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>       — paragraph
<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>–<span class="hljs-tag">&lt;<span class="hljs-name">h6</span>&gt;</span> — headings
<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>      — unordered list
<span class="hljs-tag">&lt;<span class="hljs-name">ol</span>&gt;</span>      — ordered list
<span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>      — list item
<span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span> — document section
<span class="hljs-tag">&lt;<span class="hljs-name">article</span>&gt;</span> — self-contained content
</code></pre>
<p>Common <strong>inline</strong> elements:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>    — generic inline container
<span class="hljs-tag">&lt;<span class="hljs-name">a</span>&gt;</span>       — link
<span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>  — important text (bold)
<span class="hljs-tag">&lt;<span class="hljs-name">em</span>&gt;</span>      — emphasis (italic)
<span class="hljs-tag">&lt;<span class="hljs-name">img</span>&gt;</span>     — image (technically inline by default)
<span class="hljs-tag">&lt;<span class="hljs-name">code</span>&gt;</span>    — inline code
</code></pre>
<h2 id="heading-commonly-used-html-tags">Commonly Used HTML Tags</h2>
<p>Let me walk through the tags you'll reach for in almost every project.</p>
<p><strong>Headings</strong> — <code>&lt;h1&gt;</code> through <code>&lt;h6&gt;</code></p>
<p>Headings structure your content hierarchically. <code>&lt;h1&gt;</code> is the biggest, most important heading — typically the page title. <code>&lt;h6&gt;</code> is the smallest.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My Portfolio<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Projects<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Project One<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
</code></pre>
<p>Don't pick heading levels based on how big you want the text to look. Pick them based on hierarchy. Visual size is CSS's job. Heading level communicates meaning — to the browser, to screen readers, to search engines.</p>
<p><strong>Paragraph</strong> — <code>&lt;p&gt;</code></p>
<p>The most-used tag in any content-heavy page. Every block of text gets wrapped in <code>&lt;p&gt;</code>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the first paragraph on my about page.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the second paragraph. Browsers add spacing between them.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p><strong>Links</strong> — <code>&lt;a&gt;</code></p>
<p>The "a" stands for anchor. The <code>href</code> attribute is where the link points:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://github.com"</span>&gt;</span>Visit my GitHub<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>Links are inline by default. You can put them inside paragraphs, headings, list items — anywhere.</p>
<p><strong>Images</strong> — <code>&lt;img&gt;</code></p>
<p>Two attributes are essential: <code>src</code> (the image path) and <code>alt</code> (a text description for screen readers and when the image fails to load):</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"profile.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Priyanshu smiling at a coffee shop"</span>&gt;</span>
</code></pre>
<p>Always write an <code>alt</code> attribute. It's not optional if you care about accessibility.</p>
<p><strong>Div and Span</strong> — <code>&lt;div&gt;</code> and <code>&lt;span&gt;</code></p>
<p>These are the generic containers — <code>&lt;div&gt;</code> for block-level grouping, <code>&lt;span&gt;</code> for inline grouping. They have no built-in meaning. Their entire purpose is to give you something to apply CSS classes or IDs to.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Blog Post Title<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Preview text for the <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"highlight"</span>&gt;</span>blog post<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> goes here.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>You'll use <code>&lt;div&gt;</code> constantly for layout. <code>&lt;span&gt;</code> is useful when you want to style a specific word or phrase within a larger block of text.</p>
<p><strong>Lists</strong> — <code>&lt;ul&gt;</code>, <code>&lt;ol&gt;</code>, <code>&lt;li&gt;</code></p>
<p>An unordered list renders as bullet points. An ordered list renders as numbered items. Both use <code>&lt;li&gt;</code> for each item:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>HTML<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>CSS<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>JavaScript<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">ol</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Learn HTML<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Learn CSS<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Build something<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>
</code></pre>
<h2 id="heading-a-simple-page-putting-it-together">A Simple Page Putting It Together</h2>
<p>Here's what a minimal HTML page looks like with the tags above:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My First Page<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello, World<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Welcome to my first HTML page. I built this <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>from scratch<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Things I'm Learning<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>HTML<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>CSS<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Git<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
      Check out my work on
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://github.com"</span>&gt;</span>GitHub<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>.
    <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"desk.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"My desk setup"</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Notice the structure: the <code>&lt;html&gt;</code> element wraps everything. Inside it, <code>&lt;head&gt;</code> holds metadata (like the page title that shows in the browser tab). <code>&lt;body&gt;</code> holds everything that actually renders on screen.</p>
<p>Every HTML page you write will have this skeleton.</p>
<h2 id="heading-go-look-at-real-html-right-now">Go Look at Real HTML Right Now</h2>
<p>Here's something I'd encourage you to do before you close this tab: open any webpage — any one at all — right-click somewhere on the page, and click "Inspect" or "Inspect Element."</p>
<p>The panel that opens is your browser's DevTools. The "Elements" tab shows you the live HTML structure of that page. Click on any element in the panel, and the browser will highlight the corresponding section on the page.</p>
<p>Spend five minutes clicking around. Find a <code>&lt;div&gt;</code>, find a <code>&lt;p&gt;</code>, find an <code>&lt;a&gt;</code>. See how nested elements work. See what real HTML looks like at scale.</p>
<p>This is how I actually started understanding HTML. Not from reading — from inspecting things that already existed and figuring out why they were structured the way they were.</p>
<p>The browser's inspector is your best learning tool. And now you know enough to understand what it's showing you.</p>
<hr />
<p><em>HTML is one of those things that feels big until you realise the core rules are just four: tags have angle brackets, elements are opening tag plus content plus closing tag, some elements are self-closing, and elements are either block or inline. Everything else builds on top of these four ideas.</em></p>
]]></content:encoded></item><item><title><![CDATA[Emmet for HTML: A Beginner's Guide to Writing Faster Markup]]></title><description><![CDATA[I spent the first few months of learning web development typing every HTML tag by hand. Open the file, type <div>, type </div>, go back between them, start the next line, <p>, </p>. Over and over.
I remember building a simple card component — a title...]]></description><link>https://blog.priyanshumaitra.dev/emmet-for-html-a-beginners-guide-to-writing-faster-markup</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/emmet-for-html-a-beginners-guide-to-writing-faster-markup</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Emmet]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[HTML]]></category><category><![CDATA[markup]]></category><category><![CDATA[#emmet #html #htmlelemnts #boilerplate ]]></category><category><![CDATA[webdev]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Sun, 01 Feb 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>I spent the first few months of learning web development typing every HTML tag by hand. Open the file, type <code>&lt;div&gt;</code>, type <code>&lt;/div&gt;</code>, go back between them, start the next line, <code>&lt;p&gt;</code>, <code>&lt;/p&gt;</code>. Over and over.</p>
<p>I remember building a simple card component — a title, some text, a button, wrapped in a container. Nothing complex. It took me almost ten minutes to type it all out, and most of that time wasn't thinking. It was just... typing angle brackets.</p>
<p>Then a classmate watched me do this and said, very calmly: "Why aren't you using Emmet?"</p>
<p>He typed <code>div.card&gt;h2+p+button</code> and hit Tab.</p>
<p>The entire card structure appeared. All the tags, properly nested, properly indented, in about half a second.</p>
<p>I sat there for a moment. Then I said: "What was that?"</p>
<p>This blog is the answer to that question.</p>
<h2 id="heading-what-emmet-is">What Emmet Is</h2>
<p>Emmet is a plugin — built into VS Code by default, and available for almost every other code editor — that expands short abbreviations into full HTML (and CSS) code.</p>
<p>You type a short expression that describes the structure you want. You press Tab. Emmet writes the full HTML for you.</p>
<p>That's it. No installation needed if you're on VS Code. No configuration. No learning curve beyond the abbreviation syntax itself — which is the point of this blog.</p>
<p>Emmet isn't a programming language. It's not a framework. It's a shortcut system. And the shortcut system is designed to feel like the HTML structure you're trying to create — once it clicks, you'll be surprised how natural it feels.</p>
<h2 id="heading-why-bother">Why Bother?</h2>
<p>You might be thinking: I'm still a beginner. HTML isn't hard. Why add another thing to learn?</p>
<p>Fair question. Here's my honest answer.</p>
<p>You're going to type a lot of HTML. If you work on anything real — even a personal project — you'll write the same structural patterns over and over: wrapper divs, lists of items, cards, forms, nav bars. The mechanical part of typing those tags is not where your brain should be spending energy.</p>
<p>Emmet handles the typing. You handle the thinking.</p>
<p>It also helps you think about HTML structure more clearly. When you write <code>ul&gt;li*5</code>, you're explicitly thinking "I need an unordered list with five items." That mental model is good for learning, not just for speed.</p>
<p>And practically: every professional frontend developer uses Emmet or something like it. Getting comfortable with it early means it'll be second nature by the time you're building real things.</p>
<h2 id="heading-how-emmet-works-in-vs-code">How Emmet Works in VS Code</h2>
<p>If you're on VS Code — which I'd recommend for everything in this series — Emmet is already installed and active for HTML files.</p>
<p>Open any <code>.html</code> file. Start typing an Emmet abbreviation. When you're done, press <strong>Tab</strong>. VS Code expands it.</p>
<p>That's the entire workflow. Type, Tab, done.</p>
<p>A few things worth knowing:</p>
<p>Emmet only activates in HTML (and other supported file types like JSX, Pug, etc.) by default. If you're in a <code>.js</code> file and Tab doesn't expand, that's why.</p>
<p>Sometimes VS Code shows a suggestion in the autocomplete dropdown — you can press Enter from there instead of Tab. Either works.</p>
<p>If Tab isn't expanding and you're definitely in an HTML file, check that Emmet is enabled: open VS Code settings (<code>Ctrl+,</code>), search for "Emmet: Enabled", and make sure it's on.</p>
<p>Now let's actually learn the syntax.</p>
<h2 id="heading-basic-elements-just-type-the-tag-name">Basic Elements: Just Type the Tag Name</h2>
<p>The simplest Emmet abbreviation is just the name of the HTML element you want, without the angle brackets.</p>
<p>Type this and press Tab:</p>
<pre><code>p
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>Type this and press Tab:</p>
<pre><code>h1
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
</code></pre>
<p>Type this and press Tab:</p>
<pre><code>section
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>Your cursor lands between the opening and closing tags, ready for you to type the content. Clean, fast, no angle bracket typing.</p>
<p>This works for every standard HTML element. <code>div</code>, <code>span</code>, <code>ul</code>, <code>button</code>, <code>form</code>, <code>header</code>, <code>footer</code>, <code>nav</code> — all of them.</p>
<h2 id="heading-adding-a-class-the-dot">Adding a Class: The Dot</h2>
<p>To add a class to an element, use a dot — exactly like CSS selectors.</p>
<p>Type:</p>
<pre><code>div.container
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Type:</p>
<pre><code>p.intro-text
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"intro-text"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>Multiple classes? Keep adding dots:</p>
<pre><code>div.card.featured
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card featured"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The reason Emmet uses dots for classes is intentional — it mirrors how you'd select that element in CSS (<code>.container</code>, <code>.card</code>). Once you know CSS selectors, you already half-know Emmet.</p>
<h2 id="heading-adding-an-id-the-hash">Adding an ID: The Hash</h2>
<p>Same idea, but with a hash symbol for IDs:</p>
<pre><code>div#main
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"main"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Combine with a class:</p>
<pre><code>div#app.wrapper
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Again — mirrors CSS selector syntax exactly. <code>#app.wrapper</code> in CSS would select an element with id "app" and class "wrapper". Emmet uses the same notation to create it.</p>
<h2 id="heading-attributes-square-brackets">Attributes: Square Brackets</h2>
<p>For attributes beyond class and ID — like <code>src</code>, <code>href</code>, <code>type</code>, <code>placeholder</code> — use square brackets:</p>
<pre><code>a[href=<span class="hljs-string">"https://github.com"</span>]
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://github.com"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<pre><code>input[type=<span class="hljs-string">"email"</span> placeholder=<span class="hljs-string">"Enter your email"</span>]
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your email"</span>&gt;</span>
</code></pre>
<p>Note that <code>input</code> is a void element (no closing tag), and Emmet knows this — it generates the correct self-closing form automatically.</p>
<pre><code>img[src=<span class="hljs-string">"photo.jpg"</span> alt=<span class="hljs-string">"My photo"</span>]
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"photo.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"My photo"</span>&gt;</span>
</code></pre>
<h2 id="heading-nesting-elements-the-gt-operator">Nesting Elements: The <code>&gt;</code> Operator</h2>
<p>This is where Emmet starts to feel genuinely useful. The <code>&gt;</code> operator creates a parent-child relationship — the element on the right is nested inside the element on the left.</p>
<pre><code>div&gt;p
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code>nav&gt;ul&gt;li
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
</code></pre>
<p>That three-level structure typed as nine characters. Compare that to writing it by hand:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
</code></pre>
<p>Same result, fraction of the effort. And you're explicitly thinking about the hierarchy as you write the abbreviation — <code>nav</code> contains <code>ul</code> contains <code>li</code>.</p>
<h2 id="heading-sibling-elements-the-operator">Sibling Elements: The <code>+</code> Operator</h2>
<p>The <code>+</code> operator creates sibling elements — elements at the same level, not nested.</p>
<pre><code>h1+p
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<pre><code>label+input
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span>&gt;</span>
</code></pre>
<p>Combine with nesting:</p>
<pre><code>div&gt;h2+p+button
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>A card with a heading, paragraph, and button — the structure my classmate showed me — in one abbreviation.</p>
<h2 id="heading-repeating-elements-the-operator">Repeating Elements: The <code>*</code> Operator</h2>
<p>The <code>*</code> operator repeats an element a specified number of times.</p>
<pre><code>li*<span class="hljs-number">3</span>
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
</code></pre>
<pre><code>ul&gt;li*<span class="hljs-number">5</span>
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p>Five list items, complete with the parent <code>ul</code>. Manually, that's 14 lines. With Emmet, it's seven characters.</p>
<p>Combine with classes:</p>
<pre><code>div.card*<span class="hljs-number">3</span>
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Three identical card containers. One abbreviation.</p>
<h2 id="heading-numbering-repeated-items">Numbering Repeated Items: <code>$</code></h2>
<p>When you repeat elements, you often want sequential numbers. The <code>$</code> placeholder inserts an auto-incrementing number.</p>
<pre><code>li.item-$*<span class="hljs-number">3</span>
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item-1"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item-3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
</code></pre>
<pre><code>h2.section-$*<span class="hljs-number">4</span>
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"section-1"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"section-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"section-3"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"section-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
</code></pre>
<p>Useful for generating numbered sections, slides, or any sequentially-named elements during prototyping.</p>
<h2 id="heading-adding-text-content">Adding Text Content: <code>{}</code></h2>
<p>To include text content inside the element, use curly braces:</p>
<pre><code>p{Hello, World}
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello, World<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<pre><code>a[href=<span class="hljs-string">"#"</span>]{Click here}
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>Click here<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>Combine with repetition and <code>$</code>:</p>
<pre><code>li{Item $}*<span class="hljs-number">3</span>
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item 1<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item 2<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item 3<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
</code></pre>
<p>Now you're generating both the structure and the placeholder content at the same time.</p>
<h2 id="heading-going-back-up-the-operator">Going Back Up: The <code>^</code> Operator</h2>
<p>When you're chaining with <code>&gt;</code>, you keep going deeper. The <code>^</code> operator lets you climb one level back up.</p>
<pre><code>div&gt;p&gt;span^button
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The <code>^</code> moves <code>button</code> up out of <code>&lt;p&gt;</code> and places it as a sibling of <code>&lt;p&gt;</code> inside <code>&lt;div&gt;</code>.</p>
<p>Honestly, once abbreviations get complex enough to need <code>^</code>, I often split them into two separate abbreviations instead. But for simpler structures, it's useful to know.</p>
<h2 id="heading-grouping-parentheses">Grouping: Parentheses</h2>
<p>Parentheses group parts of an abbreviation — useful when you want to repeat a multi-element structure.</p>
<pre><code>(div&gt;h2+p)*<span class="hljs-number">3</span>
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Three identical card structures — each with a heading and paragraph — from one abbreviation. This is genuinely useful when scaffolding a page with repeated sections.</p>
<h2 id="heading-the-full-html-boilerplate">The Full HTML Boilerplate: <code>!</code></h2>
<p>And here's the one that comes up in every single project. Type this into a blank <code>.html</code> file and press Tab:</p>
<pre><code>!
</code></pre><p>Just an exclamation mark.</p>
<p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>A complete, valid HTML5 boilerplate. Everything you need to start a new HTML page: doctype declaration, <code>&lt;html&gt;</code> with language attribute, <code>&lt;head&gt;</code> with charset and viewport meta tags, a <code>&lt;title&gt;</code>, and an empty <code>&lt;body&gt;</code>.</p>
<p>One character. Tab. Full boilerplate.</p>
<p>This is the abbreviation I use literally every time I start a new HTML file. If you remember nothing else from this blog, remember <code>!</code> followed by Tab.</p>
<h2 id="heading-a-real-world-example">A Real-World Example</h2>
<p>Let me put several of these together into something resembling a real component. Say I want to scaffold a simple blog post card:</p>
<pre><code>div.card&gt;img[src=<span class="hljs-string">"post.jpg"</span> alt=<span class="hljs-string">"Post image"</span>]+div.card__content&gt;h3{Post Title}+p{Post excerpt goes here.}+a[href=<span class="hljs-string">"#"</span>]{Read more}
</code></pre><p>Expands to:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"post.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Post image"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card__content"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Post Title<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Post excerpt goes here.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>Read more<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>One line. A complete, structured blog card with an image, a content container, a heading, a paragraph, and a link. Every class, every attribute, properly nested.</p>
<p>That's the power of Emmet in practice.</p>
<h2 id="heading-tips-for-getting-comfortable">Tips for Getting Comfortable</h2>
<p>Type one abbreviation at a time and watch what it expands to. Don't try to memorise everything at once. The operators you'll use 90% of the time are <code>&gt;</code>, <code>+</code>, <code>*</code>, <code>.</code>, <code>#</code>, and <code>{}</code>. Start with those.</p>
<p>Use <code>!</code> every time you start a new HTML file. It'll become muscle memory within a week.</p>
<p>When you need a structure, try writing it in Emmet first. If it doesn't work the way you expect, fall back to typing it manually. No shame in that — Emmet is a tool, not a requirement.</p>
<p>The abbreviations in this blog cover what you'll actually use day to day. There's a full Emmet cheat sheet at <code>docs.emmet.io</code> if you ever want to explore the less-common syntax.</p>
<hr />
<p><em>Emmet felt unnecessary until I started using it daily. Now typing raw HTML without it feels like writing code without autocomplete — technically possible, but slower than it needs to be. Learn the basics, use it on your next project, and it'll earn its place in your workflow.</em></p>
]]></content:encoded></item><item><title><![CDATA[CSS Selectors 101: Targeting Elements with Precision]]></title><description><![CDATA[In my early days of learning CSS, I spent a genuinely embarrassing amount of time adding styles that did nothing. I'd write color: red, save the file, refresh the browser, and the text would stay black. I'd write it again, in a slightly different pla...]]></description><link>https://blog.priyanshumaitra.dev/css-selectors-101-targeting-elements-with-precision</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/css-selectors-101-targeting-elements-with-precision</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[CSS]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[css_selector]]></category><category><![CDATA[css selectors]]></category><category><![CDATA[selectors]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Sun, 01 Feb 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>In my early days of learning CSS, I spent a genuinely embarrassing amount of time adding styles that did nothing. I'd write <code>color: red</code>, save the file, refresh the browser, and the text would stay black. I'd write it again, in a slightly different place in my stylesheet. Still black.</p>
<p>The problem wasn't the CSS property. It was the selector.</p>
<p>I was trying to style the wrong thing, or targeting elements that didn't exist the way I thought they did. CSS selectors are how you tell the browser <em>which</em> elements your styles apply to — and getting them wrong means your styles go nowhere.</p>
<p>Once I understood selectors properly, CSS clicked. Not all of it, but enough. The styles started landing. The page started looking like what I intended.</p>
<p>This blog is the thing I wish I'd read before I wasted those hours.</p>
<h2 id="heading-why-selectors-exist">Why Selectors Exist</h2>
<p>CSS stands for Cascading Style Sheets. A stylesheet contains rules. A rule looks like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">color</span>: blue;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
}
</code></pre>
<p>That rule has two parts: the selector (<code>p</code>) and the declarations (<code>color: blue; font-size: 16px;</code>).</p>
<p>The <strong>selector</strong> is the targeting mechanism. It answers the question: which elements on the page should receive these styles?</p>
<p>Without a selector, CSS has no idea where to apply your rules. A declaration without a selector is like a letter without an address — the content is there, but it has no idea where to go.</p>
<p>Think of selectors as different levels of addressing. If you're sending an announcement to everyone in a building, that's one kind of targeting. If you're sending a note specifically to the person in flat 3B, that's different — more specific, more precise. CSS selectors work the same way. Some target broadly. Some target exactly one element.</p>
<p>Let's go through them in order of specificity, starting with the broadest.</p>
<h2 id="heading-the-element-selector-everyone-with-that-name">The Element Selector: Everyone with That Name</h2>
<p>The element selector targets every instance of a particular HTML tag on the page.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.6</span>;
}
</code></pre>
<p>This applies <code>color: #333</code> and <code>line-height: 1.6</code> to <strong>every <code>&lt;p&gt;</code> element</strong> on the page. Every paragraph. All of them.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
}

<span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">color</span>: blue;
}

<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<p>Element selectors are the broadest kind. They're good for setting baseline styles — things you want to be consistent everywhere that tag appears. Font sizes for headings, base text color for paragraphs, default link colors.</p>
<p>The downside is exactly that broadness. If you want one paragraph to look different from all the others, the element selector can't help you. That's where class selectors come in.</p>
<h2 id="heading-the-class-selector-grouped-by-role">The Class Selector: Grouped by Role</h2>
<p>A class selector targets elements based on the <code>class</code> attribute in their HTML.</p>
<p>In your HTML:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"intro"</span>&gt;</span>Welcome to my blog. This is the opening paragraph.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is a regular paragraph with no special class.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"intro"</span>&gt;</span>Another intro-styled paragraph on a different page section.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>In your CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.intro</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.2rem</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">500</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#1a1a1a</span>;
}
</code></pre>
<p>The <code>.</code> before the name is what tells CSS "this is a class selector." Only elements with <code>class="intro"</code> receive these styles. The regular <code>&lt;p&gt;</code> in the middle is untouched.</p>
<p>Class selectors are the workhorse of CSS. They're reusable — the same class can be applied to as many elements as you want, and they'll all share those styles. They're flexible — you can add multiple classes to one element:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card featured"</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.card</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ddd</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.featured</span> {
  <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#0070f3</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#f0f7ff</span>;
}
</code></pre>
<p>That <code>&lt;div&gt;</code> gets styles from both <code>.card</code> and <code>.featured</code>. Classes compose. You build small, focused style rules and combine them where needed.</p>
<p>This is how most modern CSS is written. Element selectors for baselines. Class selectors for components and variations.</p>
<h2 id="heading-the-id-selector-the-unique-target">The ID Selector: The Unique Target</h2>
<p>An ID selector targets one specific element — the element with that exact <code>id</code> attribute.</p>
<p>In your HTML:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"main-header"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
</code></pre>
<p>In your CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#main-header</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#0a0a0a</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">64px</span>;
}
</code></pre>
<p>The <code>#</code> before the name marks it as an ID selector. Only the element with <code>id="main-header"</code> receives these styles.</p>
<p>The key difference between class and ID: <strong>an ID must be unique on the page.</strong> You can give the same class to dozens of elements. An ID should appear exactly once. It's an identifier — like a Social Security number for your HTML element. Every element can have one, but no two elements should share the same one.</p>
<p>Because of this uniqueness, ID selectors are typically used for major layout elements — the page header, the main content wrapper, the footer. Things that appear once.</p>
<p>Here's a comparison to make the three selectors concrete:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Element selector targets this and every other &lt;p&gt; --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Regular paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Class selector targets this and every other .highlight element --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"highlight"</span>&gt;</span>Highlighted paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

<span class="hljs-comment">&lt;!-- ID selector targets ONLY this element --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"intro-text"</span>&gt;</span>The unique opening paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-comment">/* Targets all &lt;p&gt; elements */</span>
<span class="hljs-selector-tag">p</span> { <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>; }

<span class="hljs-comment">/* Targets all elements with class="highlight" */</span>
<span class="hljs-selector-class">.highlight</span> { <span class="hljs-attribute">background</span>: yellow; }

<span class="hljs-comment">/* Targets only the element with id="intro-text" */</span>
<span class="hljs-selector-id">#intro-text</span> { <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.3rem</span>; }
</code></pre>
<h2 id="heading-group-selectors-one-rule-for-many">Group Selectors: One Rule for Many</h2>
<p>Sometimes you want the same styles applied to multiple different selectors. You could write separate rules:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span> { <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Georgia'</span>, serif; }
<span class="hljs-selector-tag">h2</span> { <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Georgia'</span>, serif; }
<span class="hljs-selector-tag">h3</span> { <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Georgia'</span>, serif; }
</code></pre>
<p>Or you can group them with a comma:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-tag">h2</span>, <span class="hljs-selector-tag">h3</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Georgia'</span>, serif;
}
</code></pre>
<p>Same result. The comma means "apply this rule to each of these selectors." It works with any combination — element selectors, class selectors, ID selectors, mixed:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-class">.section-title</span>, <span class="hljs-selector-id">#page-heading</span> {
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">700</span>;
  <span class="hljs-attribute">letter-spacing</span>: -<span class="hljs-number">0.02em</span>;
}
</code></pre>
<p>Group selectors are purely a convenience. They reduce repetition. If you find yourself writing the same declarations across multiple separate rules, group them.</p>
<h2 id="heading-descendant-selectors-targeting-by-context">Descendant Selectors: Targeting by Context</h2>
<p>Sometimes you don't just want to target an element — you want to target an element only when it's inside another specific element.</p>
<p>That's what descendant selectors do.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">article</span> <span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.8</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>;
}
</code></pre>
<p>The space between <code>article</code> and <code>p</code> is the descendant combinator. This rule applies to <code>&lt;p&gt;</code> elements that are <strong>inside</strong> an <code>&lt;article&gt;</code> element. A <code>&lt;p&gt;</code> that's outside of an <code>&lt;article&gt;</code> is not affected.</p>
<p>Here's a concrete scenario. You have a navigation bar and a main content area. Both contain links. But you want navigation links to look different from content links:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Read more about this in <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/docs"</span>&gt;</span>the documentation<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-comment">/* All links - base style */</span>
<span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">text-decoration</span>: none;
}

<span class="hljs-comment">/* Links inside nav only */</span>
<span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span> <span class="hljs-number">16px</span>;
}

<span class="hljs-comment">/* Links inside main only */</span>
<span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#0070f3</span>;
  <span class="hljs-attribute">text-decoration</span>: underline;
}
</code></pre>
<p>The two <code>nav a</code> and <code>main a</code> rules apply to completely different sets of links, even though both target <code>&lt;a&gt;</code> elements. The context — where the link lives — determines which style it gets.</p>
<p>Descendant selectors don't have to be just one level deep. <code>nav ul li a</code> would target links that are list items inside an unordered list inside a nav. The descendant relationship can be any number of levels deep.</p>
<h2 id="heading-selector-priority-when-rules-conflict">Selector Priority: When Rules Conflict</h2>
<p>Here's something that tripped me up constantly when starting out. What happens when two CSS rules target the same element with conflicting styles?</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">color</span>: black;
}

<span class="hljs-selector-class">.intro</span> {
  <span class="hljs-attribute">color</span>: blue;
}
</code></pre>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"intro"</span>&gt;</span>Which color is this?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>That paragraph has both a <code>&lt;p&gt;</code> tag and a class of <code>intro</code>. Both rules apply to it. Both set a color. Which one wins?</p>
<p>The answer is <code>blue</code> — the class selector wins. This is called <strong>specificity</strong>, and the rule is straightforward at this level:</p>
<p><strong>ID selectors beat class selectors. Class selectors beat element selectors.</strong></p>
<p>Think of it as a ranking:</p>
<pre><code>ID selector      → highest priority
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">selector</span>   → <span class="hljs-title">medium</span> <span class="hljs-title">priority</span>
<span class="hljs-title">element</span> <span class="hljs-title">selector</span> → <span class="hljs-title">lowest</span> <span class="hljs-title">priority</span></span>
</code></pre><p>More specific selectors override less specific ones, regardless of the order in the stylesheet. If you write an element selector after a class selector targeting the same property, the class selector still wins.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Even though this comes second, the class selector above still wins */</span>
<span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">color</span>: black;    <span class="hljs-comment">/* loses to .intro */</span>
}

<span class="hljs-selector-class">.intro</span> {
  <span class="hljs-attribute">color</span>: blue;     <span class="hljs-comment">/* wins over p */</span>
}
</code></pre>
<p>And an ID selector would beat both:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">p</span> { <span class="hljs-attribute">color</span>: black; }       <span class="hljs-comment">/* loses */</span>
<span class="hljs-selector-class">.intro</span> { <span class="hljs-attribute">color</span>: blue; }   <span class="hljs-comment">/* also loses */</span>
<span class="hljs-selector-id">#hero-text</span> { <span class="hljs-attribute">color</span>: red; } <span class="hljs-comment">/* wins */</span>
</code></pre>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"intro"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"hero-text"</span>&gt;</span>Red text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>This is a very high-level view of specificity — there's more to it when you get into combined selectors and the <code>!important</code> declaration. But for the selectors covered in this blog, this ranking is all you need.</p>
<h2 id="heading-putting-it-together">Putting It Together</h2>
<p>Let's look at a small real example that uses all the selector types from this blog:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"site-header"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/blog"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"active"</span>&gt;</span>Blog<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/about"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Recent Posts<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"post"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Post Title<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"excerpt"</span>&gt;</span>A short preview of the post content.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"post"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Another Post<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"excerpt"</span>&gt;</span>Another short preview.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-comment">/* Element selector - all h1s */</span>
<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1.5rem</span>;
}

<span class="hljs-comment">/* ID selector - only the site header */</span>
<span class="hljs-selector-id">#site-header</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#0a0a0a</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">16px</span> <span class="hljs-number">40px</span>;
}

<span class="hljs-comment">/* Class selector - all nav links marked active */</span>
<span class="hljs-selector-class">.active</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#0070f3</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
}

<span class="hljs-comment">/* Group selector - h1 and h2 together */</span>
<span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-tag">h2</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Georgia'</span>, serif;
}

<span class="hljs-comment">/* Descendant selector - only links inside the nav */</span>
<span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">text-decoration</span>: none;
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">24px</span>;
}

<span class="hljs-comment">/* Class selector - excerpt paragraphs */</span>
<span class="hljs-selector-class">.excerpt</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#666</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.95rem</span>;
}
</code></pre>
<p>Seven CSS rules. Every type of selector we covered. Each one targeting a specific group of elements for a specific reason.</p>
<h2 id="heading-selectors-are-the-foundation">Selectors Are the Foundation</h2>
<p>Everything you do in CSS starts with a selector. Color, spacing, typography, layout — none of it applies until you've correctly targeted the elements you want to style.</p>
<p>Getting selectors right is the difference between CSS that works and CSS that sits in your file doing nothing. Once you're comfortable with element, class, ID, group, and descendant selectors, you have the foundation to style basically anything.</p>
<p>The next step after this is pseudo-classes (<code>a:hover</code>, <code>li:first-child</code>) and pseudo-elements (<code>::before</code>, <code>::after</code>) — but those build directly on top of what we covered here. Selectors first. Everything else follows.</p>
<hr />
<p><em>A quick way to practice: open your browser DevTools, click on any element on any webpage, and look at the "Styles" panel on the right. You'll see exactly which CSS rules are applying to that element, and which selectors targeted it. That panel is the best way to understand how selectors work in practice — someone else's CSS, live, showing you the targeting in real time.</em></p>
]]></content:encoded></item><item><title><![CDATA[TCP vs UDP: When to Use What, and How TCP Relates to HTTP]]></title><description><![CDATA[In my networking course, the professor drew two boxes on the board. One labeled "TCP" and one labeled "UDP". Then he asked: "You're building a video call app. Which one do you use?"
Half the class said TCP. "It's reliable," someone explained confiden...]]></description><link>https://blog.priyanshumaitra.dev/tcp-vs-udp-when-to-use-what-and-how-tcp-relates-to-http</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/tcp-vs-udp-when-to-use-what-and-how-tcp-relates-to-http</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[computer networking]]></category><category><![CDATA[networking]]></category><category><![CDATA[TCP]]></category><category><![CDATA[tcp/ip-model]]></category><category><![CDATA[UDP]]></category><category><![CDATA[http]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Sat, 31 Jan 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>In my networking course, the professor drew two boxes on the board. One labeled "TCP" and one labeled "UDP". Then he asked: "You're building a video call app. Which one do you use?"</p>
<p>Half the class said TCP. "It's reliable," someone explained confidently. "You want to make sure all packets arrive."</p>
<p>The professor shook his head. "You'd use UDP."</p>
<p>Confused silence.</p>
<p>"But what if packets get lost?" someone asked.</p>
<p>"In a live video call, you'd rather drop a frame than freeze the call waiting for a lost packet to be resent."</p>
<p>That was the moment TCP vs UDP stopped being abstract terms and became a real engineering decision. And that's what this blog is about — not what these protocols <em>are</em> at a byte level, but how they <em>behave</em>, when to choose one over the other, and how HTTP fits into all of this.</p>
<h2 id="heading-the-internet-needs-rules-for-sending-data">The Internet Needs Rules for Sending Data</h2>
<p>Before TCP or UDP, let's talk about the problem they both solve.</p>
<p>When you send data across the internet, it doesn't travel as one big chunk. It gets broken into small pieces called <strong>packets</strong>. Each packet travels independently — possibly through different routes — and gets reassembled at the destination.</p>
<p>This creates problems. Packets can arrive out of order. They can get lost entirely. They can arrive corrupted. The internet's physical infrastructure doesn't guarantee anything — it's what networking people call a <em>best-effort</em> network.</p>
<p>TCP and UDP are two different answers to this chaos. Two protocols that sit on top of the internet's physical layer and impose different sets of rules on how data moves.</p>
<p>One chooses safety. The other chooses speed. Neither is wrong. They just solve different problems.</p>
<h2 id="heading-tcp-the-safe-reliable-option">TCP: The Safe, Reliable Option</h2>
<p>TCP stands for Transmission Control Protocol. The word that matters most here is <em>control</em>.</p>
<p>Before TCP sends a single byte of your actual data, it does a handshake — a three-step greeting between your computer and the server:</p>
<ol>
<li><p>Your computer sends: "I want to connect." (SYN)</p>
</li>
<li><p>Server responds: "Okay, connection acknowledged." (SYN-ACK)</p>
</li>
<li><p>Your computer confirms: "Got it, let's go." (ACK)</p>
</li>
</ol>
<p>Now the connection is established. Only then does data start flowing.</p>
<p>And as data flows, TCP does more work:</p>
<ul>
<li><p><strong>Acknowledgements</strong>: Every packet sent gets acknowledged by the receiver. "Got packet 1. Got packet 2. Got packet 3." If the sender doesn't receive an acknowledgement in time, it assumes the packet was lost and resends it.</p>
</li>
<li><p><strong>Ordering</strong>: Packets arrive in the correct sequence even if they traveled different routes and arrived out of order.</p>
</li>
<li><p><strong>Flow control</strong>: TCP monitors how fast data is being sent and slows down if the receiver is getting overwhelmed.</p>
</li>
<li><p><strong>Error checking</strong>: Corrupted data gets detected and discarded, triggering a resend.</p>
</li>
</ul>
<p>Think of TCP as a courier service with tracking. You hand over a package. The courier gives you a receipt. At every step, there's confirmation. If the package gets lost in transit, the courier goes back, gets a new one, and tries again. The package <em>will</em> arrive, intact, in the right order. You just have to wait for it.</p>
<p>The tradeoff? All that reliability adds overhead. More round trips. More waiting for acknowledgements. More latency.</p>
<h2 id="heading-udp-the-fast-fire-and-forget-option">UDP: The Fast, Fire-and-Forget Option</h2>
<p>UDP stands for User Datagram Protocol. No handshake. No acknowledgements. No ordering. No guaranteed delivery.</p>
<p>You send a packet. It either arrives or it doesn't. You have no way of knowing which.</p>
<p>That sounds terrible until you think about when it's actually fine — even preferable.</p>
<p>Think of UDP as a radio broadcast. The station transmits. Whatever reaches your radio, reaches it. If there's static and you miss a word, the station doesn't stop and replay it. The broadcast just continues. You hear what you hear.</p>
<p>UDP is:</p>
<ul>
<li><p><strong>Connectionless</strong>: No handshake required. Data starts flowing immediately.</p>
</li>
<li><p><strong>Unreliable</strong>: No acknowledgements. Packets can be lost, duplicated, or arrive out of order.</p>
</li>
<li><p><strong>Fast</strong>: Less overhead means less latency.</p>
</li>
<li><p><strong>Lightweight</strong>: No connection state to maintain on either end.</p>
</li>
</ul>
<p>For situations where speed matters more than completeness, UDP wins. For situations where every single byte matters, TCP wins.</p>
<h2 id="heading-the-key-differences-side-by-side">The Key Differences, Side by Side</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Factors</td><td>TCP</td><td>UDP</td></tr>
</thead>
<tbody>
<tr>
<td>Connection</td><td>Requires handshake</td><td>Connectionless</td></tr>
<tr>
<td>Reliability</td><td>Guaranteed delivery</td><td>Best-effort, no guarantee</td></tr>
<tr>
<td>Ordering</td><td>Packets arrive in order</td><td>No ordering</td></tr>
<tr>
<td>Speed</td><td>Slower (more overhead)</td><td>Faster (minimal overhead)</td></tr>
<tr>
<td>Use case</td><td>Where accuracy matters</td><td>Where speed matters</td></tr>
<tr>
<td>Overhead</td><td>High</td><td>Low</td></tr>
</tbody>
</table>
</div><h2 id="heading-when-to-use-tcp">When to Use TCP</h2>
<p>Use TCP whenever losing data is unacceptable.</p>
<p><strong>Web browsing</strong>: When you load a webpage, every byte of HTML, CSS, and JavaScript needs to arrive correctly. A missing chunk of your CSS file would make the page look broken. HTTP — which powers all web communication — runs on top of TCP for this reason.</p>
<p><strong>File transfers</strong>: Downloading an image, a PDF, or a zip file. One missing or corrupted packet and the file is useless. FTP and SFTP both use TCP.</p>
<p><strong>Email</strong>: SMTP, IMAP, POP3 — all TCP. Every word of every email needs to arrive.</p>
<p><strong>Database connections</strong>: When your application talks to a PostgreSQL or MySQL server, that connection runs over TCP. Losing a query or a result mid-transfer would cause data corruption.</p>
<p><strong>SSH</strong>: Remote terminal sessions need every character to arrive in the right order. You can't have commands arriving scrambled.</p>
<p>The pattern: any time you're transferring data where partial delivery is worse than slow delivery, TCP is the right call.</p>
<h2 id="heading-when-to-use-udp">When to Use UDP</h2>
<p>Use UDP when speed and real-time delivery matter more than perfection.</p>
<p><strong>Live video and audio calls</strong>: Zoom, Google Meet, WhatsApp calls — all UDP. If a packet is lost during a video call, you see a brief glitch. That's far better than the alternative: TCP would pause the stream and wait for the lost packet to be resent, causing a freeze. A one-second freeze in a call is worse than a one-frame glitch.</p>
<p><strong>Online gaming</strong>: In a multiplayer game, your character's position needs to be updated many times per second. If a position update from 200ms ago gets lost, you don't want to wait for it. You want the current position. Old data is worthless in real-time games.</p>
<p><strong>Live streaming</strong>: YouTube Live, Twitch — UDP-based. A dropped frame in a live stream is invisible to the viewer. Waiting to resend it would cause buffering, which is far more disruptive.</p>
<p><strong>DNS queries</strong>: Small, fast lookups. If a DNS query gets lost, the client just sends another one. The overhead of a TCP connection for something this small would be wasteful.</p>
<p><strong>IoT sensors</strong>: Temperature sensors, GPS trackers — sending small, frequent updates where missing one reading is fine as long as the next one arrives.</p>
<p>The pattern: real-time data where a late packet is as useless as a lost one.</p>
<h2 id="heading-a-real-world-comparison">A Real-World Comparison</h2>
<p>Let me make this concrete with a scenario I think about a lot: building two different features in the same app.</p>
<p><strong>Feature 1: User uploads a profile picture.</strong> This needs TCP. If three packets from the image data arrive and one is missing, the image is corrupted. We can't show a broken image. We need every byte, in order, guaranteed. We wait. We retry. We use TCP.</p>
<p><strong>Feature 2: Live location sharing in a delivery app.</strong> This needs UDP. The driver's GPS coordinates update every second. If the update at 2:00:01 PM gets lost, I don't want to wait for it. By the time it would be resent, the driver has already moved. I want the 2:00:02 PM update. Old location data is useless. Use UDP.</p>
<p>Same app. Same backend. Different transport protocols for different features, based on what each feature actually needs.</p>
<h2 id="heading-what-is-http-and-where-it-fits">What is HTTP and Where It Fits</h2>
<p>This is where a very common confusion lives.</p>
<p>People often talk about HTTP and TCP in the same breath, or use them interchangeably in casual conversation. They're not the same thing. They exist at different layers and do different things.</p>
<p>HTTP — HyperText Transfer Protocol — is an <strong>application-layer protocol</strong>. It defines how requests and responses are formatted when a browser communicates with a web server. When your browser wants an HTML page, it sends an HTTP request:</p>
<pre><code class="lang-plaintext">GET /index.html HTTP/1.1
Host: myportfolio.tech
Accept: text/html
</code></pre>
<p>The server receives this, processes it, and sends back an HTTP response:</p>
<pre><code class="lang-plaintext">HTTP/1.1 200 OK
Content-Type: text/html

&lt;html&gt;...&lt;/html&gt;
</code></pre>
<p>HTTP defines the format of these messages — the method (GET, POST, PUT), the headers, the status codes (200 OK, 404 Not Found, 500 Server Error), the body. It's a language that browsers and servers agreed to speak.</p>
<p>What HTTP does <em>not</em> do: it has no idea how to actually move bytes from your browser to the server and back. It doesn't handle packet splitting, sequencing, acknowledgements, or retransmission. That's not its job.</p>
<p>That's TCP's job.</p>
<h2 id="heading-the-relationship-between-http-and-tcp">The Relationship Between HTTP and TCP</h2>
<p>HTTP runs <em>on top of</em> TCP. When a browser makes an HTTP request, the sequence goes like this:</p>
<ol>
<li><p><strong>TCP does the transport work first.</strong> A connection is established via the three-way handshake. A reliable channel now exists between the browser and the server.</p>
</li>
<li><p><strong>HTTP uses that channel.</strong> The browser sends its HTTP request through the TCP connection. The server sends its HTTP response through the same TCP connection.</p>
</li>
<li><p><strong>TCP ensures delivery.</strong> If any packet gets lost in transit, TCP handles the retransmission. HTTP never knows this happened. From HTTP's perspective, it just handed data to TCP and received data from TCP.</p>
</li>
</ol>
<p>Think of it in layers:</p>
<pre><code class="lang-plaintext">Your browser (HTTP)
    ↓  "GET /index.html"
TCP (transport layer)
    ↓  establishes connection, guarantees delivery
IP (internet layer)
    ↓  routes packets across networks
Physical network
    ↓  actual cables, wireless signals
Server
</code></pre>
<p>HTTP is the language. TCP is the postal system that reliably delivers the letters. They're partners — each doing a job the other doesn't.</p>
<p>This is why "Is HTTP the same as TCP?" is a bit like asking "Is English the same as sound waves?" No — English is what you say, sound waves are how your voice travels through air to reach someone's ears. HTTP is what you send, TCP is how it gets there reliably.</p>
<h2 id="heading-http3-changed-this-briefly">HTTP/3 Changed This — Briefly</h2>
<p>Worth a quick mention: HTTP/3, the latest version of HTTP, switched from TCP to QUIC — a protocol built on top of UDP. The goal was to reduce the latency that TCP's handshake and reliability mechanisms add.</p>
<p>QUIC reimplements reliability on top of UDP, but smarter — if one data stream is blocked (a slow CSS file), it doesn't block other streams (your HTML, your images). TCP's reliability is connection-wide; QUIC's is per-stream.</p>
<p>The foundational mental model stays the same: HTTP is the application layer, and whatever carries it — TCP or QUIC — is the transport layer below.</p>
<h2 id="heading-the-short-version">The Short Version</h2>
<p>If you had to summarise this blog in four sentences:</p>
<p>TCP is reliable but adds overhead. UDP is fast but drops packets. Use TCP when you can't afford to lose data. Use UDP when you can't afford the delay of waiting for lost data.</p>
<p>HTTP is the language browsers and servers speak. TCP is the infrastructure that carries those conversations reliably. They operate at different layers and do different jobs. Neither replaces the other.</p>
<hr />
<p><em>Networking protocols feel abstract until you start building things that depend on them. Understanding TCP vs UDP stops being academic the first time you have to decide why your video stream freezes or why your file download corrupted. The answer is almost always in the transport layer.</em></p>
]]></content:encoded></item><item><title><![CDATA[TCP Working: 3-Way Handshake and Reliable Communication]]></title><description><![CDATA[Last semester, a friend of mine was debugging why his Flask app kept throwing connection errors against a remote database. He spent two hours checking his Python code, his SQL queries, his .env file. The code was fine. The queries were fine. The cred...]]></description><link>https://blog.priyanshumaitra.dev/tcp-working-3-way-handshake-and-reliable-communication</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/tcp-working-3-way-handshake-and-reliable-communication</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[computer networking]]></category><category><![CDATA[networking]]></category><category><![CDATA[TCP]]></category><category><![CDATA[TCP Handshake]]></category><category><![CDATA[tcp/ip-model]]></category><category><![CDATA[tcp-3-way-handshake]]></category><category><![CDATA[TCP/IP]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Sat, 31 Jan 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>Last semester, a friend of mine was debugging why his Flask app kept throwing connection errors against a remote database. He spent two hours checking his Python code, his SQL queries, his .env file. The code was fine. The queries were fine. The credentials were fine.</p>
<p>The problem was a firewall rule blocking TCP port 5432.</p>
<p>When I explained this to him, he asked: "So TCP is just about ports?"</p>
<p>It's not. Not even close. TCP is one of the most carefully designed protocols in computing, and understanding it properly changes how you debug, how you design systems, and how you reason about what "reliable" actually means in networking.</p>
<p>This blog is about what TCP does under the hood — not at the byte level, but at the behavioral level. What it negotiates before sending a single byte of your data. How it tracks every packet. How it handles loss. How it closes gracefully.</p>
<h2 id="heading-what-is-tcp-and-why-it-exists">What is TCP and Why It Exists</h2>
<p>The internet is, at its core, unreliable. Packets travel through routers they've never met, across cables they can't predict, arriving (or not) in orders that weren't planned. The physical network doesn't guarantee anything.</p>
<p>TCP — Transmission Control Protocol — is the answer to this unreliability. It's a protocol that sits on top of the internet's routing layer and adds a contract between two machines: "I promise that everything I send, you will receive, in order, without corruption. And if something goes wrong in transit, I'll fix it without you even knowing."</p>
<p>That's a big promise. Keeping it requires a lot of machinery — handshakes, sequence numbers, acknowledgements, retransmission timers. Let's go through each.</p>
<h2 id="heading-problems-tcp-is-designed-to-solve">Problems TCP Is Designed to Solve</h2>
<p>Before understanding the solution, let's understand the specific problems.</p>
<p><strong>Packets arrive out of order.</strong> The internet routes packets independently. Packet 3 might arrive before packet 1 if it took a faster route. Your application would read garbled data if nobody reassembled them in the right sequence.</p>
<p><strong>Packets get lost.</strong> Routers drop packets when congested. Wireless connections lose packets to interference. There's no built-in retry at the network layer.</p>
<p><strong>Packets arrive corrupted.</strong> Bit flips happen. If a single bit flips in a file you're downloading, you want to detect it and get a clean copy — not silently accept broken data.</p>
<p><strong>Sender overwhelms the receiver.</strong> If a powerful server blasts data at a slow device, the device's buffer overflows and packets are dropped. Someone needs to regulate speed.</p>
<p><strong>No connection state.</strong> Without TCP, there's no concept of "is the other side even running?" You're just firing packets into the void.</p>
<p>TCP solves all of these. Let's see how it starts — with the handshake.</p>
<h2 id="heading-the-3-way-handshake-establishing-trust">The 3-Way Handshake: Establishing Trust</h2>
<p>Before a single byte of your application's data moves, TCP performs a 3-step ritual between the two machines. This is called the Three-Way Handshake, and it establishes the connection with mutual agreement.</p>
<p>Here's the best analogy I've found. Imagine you call a friend on the phone:</p>
<ul>
<li><p>You: "Hey, can you hear me?" <em>(SYN)</em></p>
</li>
<li><p>Friend: "Yeah, I can hear you. Can you hear me?" <em>(SYN-ACK)</em></p>
</li>
<li><p>You: "Yep, all good. Let's talk." <em>(ACK)</em></p>
</li>
</ul>
<p>Now both of you know the channel works in both directions. You didn't just assume. You verified. The conversation can begin.</p>
<p>TCP does exactly this, except both sides also exchange sequence numbers — a starting point for tracking packets — during this handshake.</p>
<h2 id="heading-step-by-step-syn-syn-ack-ack">Step-by-Step: SYN, SYN-ACK, ACK</h2>
<p>Let's walk through it concretely. Your browser wants to connect to a web server.</p>
<hr />
<p><strong>Step 1 — SYN (Synchronise)</strong></p>
<p>Your browser sends a TCP segment to the server with the SYN flag set. Alongside this, it sends its <strong>Initial Sequence Number (ISN)</strong> — a randomly chosen number, let's call it <code>x</code>.</p>
<p>What this says: "I want to connect. My sequence numbers will start at <code>x</code>. Are you there?"</p>
<p>The server receives this. The connection is now half-open on the server's side — it knows the client wants to connect, but hasn't confirmed it can yet.</p>
<hr />
<p><strong>Step 2 — SYN-ACK (Synchronise-Acknowledge)</strong></p>
<p>The server responds with both the SYN and ACK flags set. It does two things:</p>
<ul>
<li><p>Acknowledges your SYN: "I received your request, and I'm expecting your next byte to have sequence number <code>x+1</code>."</p>
</li>
<li><p>Sends its own Initial Sequence Number: <code>y</code>. "My sequence numbers will start at <code>y</code>."</p>
</li>
</ul>
<p>What this says: "Got you. I'm here. Let's synchronise. Your data starts at <code>x+1</code>, mine starts at <code>y</code>."</p>
<hr />
<p><strong>Step 3 — ACK (Acknowledge)</strong></p>
<p>Your browser sends back a final ACK:</p>
<ul>
<li>Acknowledges the server's SYN: "Got your sequence number <code>y</code>. Expecting <code>y+1</code> next from you."</li>
</ul>
<p>What this says: "Perfect. I heard you. We're both synchronised. Connection established."</p>
<p>Three messages. Both sides have confirmed the channel works in both directions. Both sides know each other's starting sequence numbers. The connection is live.</p>
<pre><code class="lang-plaintext">Client                          Server
  |                               |
  |  ------ SYN (seq=x) ------&gt;   |
  |                               |
  |  &lt;-- SYN-ACK (seq=y,ack=x+1)  |
  |                               |
  |  ------ ACK (ack=y+1) -----&gt;  |
  |                               |
  |     Connection Established    |
</code></pre>
<p>This is why TCP connections have latency before data flows. The round trip of these three messages adds time. On a high-latency connection, this is measurable. It's one reason HTTP/3 moved to QUIC — QUIC can sometimes establish connections with zero round trips for returning clients.</p>
<h2 id="heading-how-data-transfer-works-in-tcp">How Data Transfer Works in TCP</h2>
<p>Now the connection exists. Your browser starts sending your HTTP request. How does TCP handle the actual data?</p>
<p><strong>Sequence Numbers and Acknowledgements</strong></p>
<p>Every byte TCP sends has a sequence number. If the browser sends 1,000 bytes starting from sequence number 100, those bytes are numbered 100 through 1,099.</p>
<p>The receiver — the server — sends back an ACK for every segment received. The ACK number says: "I've received everything up to this point. Send me the next byte starting from this number."</p>
<p>If the server received bytes 100–1,099 successfully, it sends ACK 1100: "Got everything. Send me 1100 next."</p>
<p>This continuous loop — send, acknowledge, send, acknowledge — is how TCP tracks that data arrived safely.</p>
<p><strong>Windowing: Not Waiting After Every Packet</strong></p>
<p>Here's something that would otherwise make TCP impractically slow: if the sender had to wait for an ACK after every single packet, the round-trip time would dominate everything. You'd be waiting constantly.</p>
<p>TCP uses a <strong>sliding window</strong> to solve this. The sender can have multiple packets "in flight" simultaneously — sent but not yet acknowledged — up to a limit called the window size.</p>
<p>Think of it like ordering at a restaurant. You don't place one item, wait for it to arrive, eat it, then order the next. You order everything at once and it comes as it's ready. The window is how many dishes can be on their way to your table at the same time.</p>
<p>The window size can grow over time as the connection proves reliable — TCP starts conservatively and speeds up. This is called <strong>slow start</strong>, and it's the algorithm behind why your download often accelerates after the first second.</p>
<h2 id="heading-how-tcp-ensures-reliability-order-and-correctness">How TCP Ensures Reliability, Order, and Correctness</h2>
<p><strong>Handling Lost Packets: Retransmission</strong></p>
<p>What happens if a packet is lost? The receiver simply doesn't send an ACK for it.</p>
<p>The sender has a <strong>retransmission timer</strong> ticking for every unacknowledged packet. If the timer expires and no ACK arrived, the sender assumes the packet was lost and resends it.</p>
<p>There's also a faster mechanism: <strong>duplicate ACKs</strong>. If the receiver gets packet 5 after already receiving packets 1, 2, 3, it ACKs the last successfully received in-order packet — say, ACK 3. If the sender gets three of these duplicate ACKs, it doesn't wait for the timer. It knows packet 4 is missing and retransmits immediately. This is called <strong>fast retransmit</strong>.</p>
<p>Your application never sees this. As far as HTTP or your database driver is concerned, the bytes just arrived. TCP handled the loss and recovery silently.</p>
<p><strong>Ordering</strong></p>
<p>Because every byte has a sequence number, the receiver can always put packets back in the right order regardless of when they arrived. Got packet 5 before packet 3? Buffer packet 5, wait for packet 3, reassemble in order, deliver to the application in sequence.</p>
<p><strong>Error Detection: Checksums</strong></p>
<p>Every TCP segment includes a checksum — a number computed from the data in that segment. The receiver recalculates this checksum and compares it to the received value. If they don't match, the segment is silently discarded. The sender's retransmission timer handles the rest.</p>
<p>Corruption detected. Bad data never reaches your application.</p>
<p><strong>Flow Control</strong></p>
<p>The receiver tells the sender how much buffer space it has left using a field called the <strong>receive window</strong>. If the receiver's buffer is filling up, it shrinks this window, signalling the sender to slow down. If the buffer empties, it expands the window.</p>
<p>This prevents a fast sender from overwhelming a slow receiver. The sender adapts its pace dynamically based on what the receiver can handle.</p>
<h2 id="heading-how-a-tcp-connection-is-closed">How a TCP Connection Is Closed</h2>
<p>Closing a TCP connection is also a negotiated process — and it's four steps, not three. This is called the <strong>4-Way Teardown</strong> (or FIN handshake).</p>
<p>Why four steps? Because TCP connections are <strong>full-duplex</strong> — both sides send data independently. Closing one direction doesn't close the other. Each side has to independently signal that it's done sending.</p>
<pre><code class="lang-plaintext">Client                          Server
  |                               |
  |  ------- FIN ------------&gt;    |  "I'm done sending"
  |                               |
  |  &lt;------ ACK -------------    |  "Got it"
  |                               |
  |  &lt;------ FIN -------------    |  "I'm done sending too"
  |                               |
  |  ------- ACK ------------&gt;    |  "Got it. Goodbye."
  |                               |
  |        Connection Closed       |
</code></pre>
<p>After the client sends FIN, it enters a <strong>TIME_WAIT</strong> state before fully closing. This wait (typically 2 minutes) ensures any delayed packets from the old connection don't confuse a new one using the same port. If you've ever restarted a server and gotten "Address already in use", that's TIME_WAIT.</p>
<p>The server can also send data after receiving a FIN from the client — that's what full-duplex means. The client said "I'm done sending", not "stop everything." The server might still have data to finish sending before it sends its own FIN.</p>
<h2 id="heading-putting-it-all-together">Putting It All Together</h2>
<p>Here's the full lifecycle of a TCP connection for a single HTTP request, start to finish:</p>
<pre><code class="lang-plaintext">1. 3-Way Handshake
   SYN → SYN-ACK → ACK
   (Connection established)

2. Data Transfer
   HTTP request sent with sequence numbers
   Server ACKs received segments
   Server sends HTTP response
   Client ACKs received segments
   (Retransmission happens if anything is lost)

3. 4-Way Teardown
   FIN → ACK → FIN → ACK
   (Connection closed gracefully)
</code></pre>
<p>Every HTTP request your browser makes goes through this. Every database query your application sends goes through this. Every SSH command you type goes through this.</p>
<h2 id="heading-what-this-changes-about-how-you-debug">What This Changes About How You Debug</h2>
<p>When I told my friend his problem was a firewall blocking port 5432, he understood it differently after learning about the handshake. The firewall was dropping the SYN packet before it reached the database server. The handshake never completed. The connection never established. The Python driver kept timing out waiting for a SYN-ACK that would never come.</p>
<p>Once you understand the handshake, errors like "connection refused", "connection timed out", and "connection reset" stop being mysterious.</p>
<ul>
<li><p><strong>Connection refused</strong>: The port is reachable but nothing is listening on it. The OS sends back a RST (reset) immediately.</p>
</li>
<li><p><strong>Connection timed out</strong>: The SYN went out but no SYN-ACK ever arrived. Firewall, wrong IP, server unreachable.</p>
</li>
<li><p><strong>Connection reset</strong>: Something sent a RST mid-connection — often a firewall or a server that forcibly closed the connection.</p>
</li>
</ul>
<p>The handshake is the diagnostic entry point. If it doesn't complete, nothing else matters. And now you know exactly what to look for.</p>
<hr />
<p><em>TCP is one of those protocols that rewards understanding. You don't interact with it directly as an application developer — it's invisible by design. But when things go wrong at the network level, it's almost always the handshake that tells you why.</em></p>
]]></content:encoded></item><item><title><![CDATA[How a Browser Works: A Beginner-Friendly Guide to Browser Internals]]></title><description><![CDATA[I used to think browsers were just windows. Open Chrome, type a URL, website appears. Simple.
Then in my second year, my professor asked us to explain what happens between pressing Enter and seeing the page. I said something like: "The browser fetche...]]></description><link>https://blog.priyanshumaitra.dev/how-a-browser-works-a-beginner-friendly-guide-to-browser-internals</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/how-a-browser-works-a-beginner-friendly-guide-to-browser-internals</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[computer networking]]></category><category><![CDATA[Browsers]]></category><category><![CDATA[Browser Internals]]></category><category><![CDATA[url]]></category><category><![CDATA[BrowserEngine]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Fri, 30 Jan 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>I used to think browsers were just windows. Open Chrome, type a URL, website appears. Simple.</p>
<p>Then in my second year, my professor asked us to explain what happens between pressing Enter and seeing the page. I said something like: "The browser fetches the HTML and shows it." He nodded slowly in that way professors do when they're being polite about a terrible answer.</p>
<p>The real answer took me weeks to piece together. And once I did, I genuinely started looking at browsers differently — not as windows, but as some of the most sophisticated software ever built. Your browser does more work in two seconds than most programs do in their entire lifetime.</p>
<p>Let me walk you through it. We'll go layer by layer, no specification pages, no jargon avalanches. Just how it actually works.</p>
<h2 id="heading-what-a-browser-actually-is">What a Browser Actually Is</h2>
<p>Most people describe a browser as "software that opens websites." That's like calling a car "a seat that moves." Technically accurate. Completely misses the point.</p>
<p>A browser is a platform — a complex application that fetches resources from the internet, interprets multiple programming languages simultaneously, constructs a visual representation of those resources, and renders it on your screen, all while handling user interactions in real time.</p>
<p>It speaks HTTP to fetch files. It understands HTML, CSS, and JavaScript. It has its own layout engine, rendering pipeline, JavaScript runtime, and networking stack. It manages memory, security sandboxes, and multiple processes running in parallel.</p>
<p>All of that fires up every time you type a URL.</p>
<h2 id="heading-the-main-parts-before-we-dive-in">The Main Parts, Before We Dive In</h2>
<p>Before going deep, here's the high-level map. Think of a browser as a team where each member has one job:</p>
<p><strong>User Interface (UI)</strong>: Everything you see and interact with that isn't the webpage itself. The address bar, the tabs, the back button, the bookmarks bar.</p>
<p><strong>Browser Engine</strong>: The coordinator. Takes input from the UI, passes it to the rendering engine, manages communication between components.</p>
<p><strong>Rendering Engine</strong>: The core worker. Takes HTML, CSS, and other resources and figures out what to draw on screen.</p>
<p><strong>Networking Layer</strong>: Handles all HTTP/HTTPS requests — fetching HTML files, CSS files, images, JavaScript.</p>
<p><strong>JavaScript Engine</strong>: Parses and executes JavaScript. Chrome uses V8. Firefox uses SpiderMonkey.</p>
<p><strong>Data Storage</strong>: Cookies, localStorage, IndexedDB, cache — the browser's memory for persistent data.</p>
<p>These components hand work to each other in a pipeline. Understanding that pipeline is what this blog is about.</p>
<h2 id="heading-the-user-interface-the-part-you-know">The User Interface: The Part You Know</h2>
<p>The UI is everything you interact with before the webpage loads — address bar, back/forward buttons, reload, bookmarks, tabs.</p>
<p>The UI and webpage content are intentionally separated. The browser's address bar is not part of the webpage. This matters for security — a website can't fake your browser chrome to spoof URLs (at least not through normal means).</p>
<p>When you type a URL and press Enter, the UI hands that URL to the browser engine. That's when the real work starts.</p>
<h2 id="heading-browser-engine-vs-rendering-engine">Browser Engine vs Rendering Engine</h2>
<p>These two get confused constantly, even in technical writing. Here's the simple version:</p>
<p>The <strong>browser engine</strong> is the glue. It sits between the UI and the rendering engine, coordinating communication. When you press back, it's the browser engine that tells the rendering engine to load the previous page. It manages navigation, history, and coordinates between components.</p>
<p>The <strong>rendering engine</strong> is the builder. It takes raw HTML and CSS and converts them into something visual. This is where your webpage actually gets constructed and drawn.</p>
<p>Different browsers use different rendering engines:</p>
<ul>
<li><p>Chrome and Edge use <strong>Blink</strong></p>
</li>
<li><p>Firefox uses <strong>Gecko</strong></p>
</li>
<li><p>Safari uses <strong>WebKit</strong> (Blink was actually forked from WebKit)</p>
</li>
</ul>
<p>You don't need to memorize which engine does what internally. The important thing is understanding the flow that all of them follow. That flow is remarkably similar across every browser.</p>
<h2 id="heading-networking-fetching-the-raw-material">Networking: Fetching the Raw Material</h2>
<p>You pressed Enter. The networking layer takes over.</p>
<p>DNS resolution happens first — the domain gets converted to an IP address (exactly what we covered in the DNS resolution blog: root → TLD → authoritative nameserver). Then the browser opens a TCP connection to that IP and sends an HTTP request:</p>
<pre><code class="lang-plaintext">GET /index.html HTTP/1.1
Host: google.com
Accept: text/html
</code></pre>
<p>The server responds with the HTML file as a stream of bytes. The browser starts working on it immediately, even before the full file arrives.</p>
<p>While parsing HTML, the browser discovers more resources — a CSS file in <code>&lt;link&gt;</code>, JavaScript in <code>&lt;script&gt;</code>, images in <code>&lt;img&gt;</code>. Each triggers another network request. Modern browsers have a <strong>preload scanner</strong> that reads ahead in the HTML while the main parser is busy, fetching CSS and JS files early so requests overlap instead of queue up.</p>
<h2 id="heading-html-parsing-building-the-dom">HTML Parsing: Building the DOM</h2>
<p>The raw HTML the browser receives is just text. A string of characters. The browser needs to make it meaningful.</p>
<p>This process is called <strong>parsing</strong>. Let me explain parsing with something simpler first.</p>
<p>Consider this math expression: <code>3 + 4 × 2</code></p>
<p>You don't evaluate it left to right. You know multiplication comes before addition. You understand the structure — the rules — and evaluate accordingly: <code>3 + 8 = 11</code>.</p>
<p>Parsing is the same idea. Take a flat sequence of characters, understand the rules of the language, and extract the structure.</p>
<p>For HTML, the parser reads character by character, identifies tags, attributes, and text content, and converts them into a structured tree. Take this HTML:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello World<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is a paragraph.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The parser turns this into a tree structure:</p>
<pre><code class="lang-plaintext">Document
└── html
    └── body
        ├── h1
        │   └── "Hello World"
        └── p
            └── "This is a paragraph."
</code></pre>
<p>This tree is called the <strong>DOM</strong> — Document Object Model. Every element in your HTML becomes a node in this tree. Every piece of text becomes a node. Even HTML comments become nodes.</p>
<p>The DOM is not your HTML file. It's a live, in-memory tree representation that the browser builds from your HTML. This is an important distinction. When JavaScript manipulates the DOM with <code>document.querySelector()</code> or <code>element.innerHTML</code>, it's operating on this tree in memory — not modifying your actual HTML file.</p>
<p>One thing I found interesting: HTML parsing is intentionally forgiving. If you write broken HTML, the parser doesn't crash. It makes its best guess and continues. That's why badly-written HTML often still renders — the browser is quietly fixing your mistakes.</p>
<h2 id="heading-css-parsing-building-the-cssom">CSS Parsing: Building the CSSOM</h2>
<p>While HTML is being parsed (or sometimes after, depending on where your <code>&lt;link&gt;</code> tag is), the browser fetches and parses CSS files.</p>
<p>CSS parsing works similarly to HTML parsing but produces a different tree — the <strong>CSSOM</strong>, which stands for CSS Object Model.</p>
<p>Take this CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
}

<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">color</span>: blue;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">32px</span>;
}

<span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">color</span>: gray;
}
</code></pre>
<p>The browser parses these rules and builds a tree where styles cascade down from parent elements to children. This is what the "Cascading" in Cascading Style Sheets actually means — styles inherit and override as you go down the tree.</p>
<p>Here's something important that tripped me up early: <strong>CSS blocks rendering.</strong> The browser will not render the page until it has fetched and parsed all CSS files. It needs the complete CSSOM before it can draw anything, because any CSS file could override any style.</p>
<p>This is why putting <code>&lt;link rel="stylesheet"&gt;</code> in the <code>&lt;head&gt;</code> matters. It gives the browser a chance to fetch CSS early. And it's why large, slow-loading CSS files make your page feel slow — the entire render is waiting for that CSS to arrive and be parsed.</p>
<h2 id="heading-render-tree-dom-meets-cssom">Render Tree: DOM Meets CSSOM</h2>
<p>Now you have two trees: the DOM (structure) and the CSSOM (styles). The browser combines them into a third structure called the <strong>Render Tree</strong>.</p>
<p>The Render Tree contains only the elements that will actually be visible on screen. It merges each DOM node with its computed styles from the CSSOM.</p>
<p>This is where some elements get excluded. <code>&lt;head&gt;</code> elements — <code>&lt;title&gt;</code>, <code>&lt;meta&gt;</code>, <code>&lt;link&gt;</code> — are in the DOM but not the Render Tree, because they don't render visually. Elements with <code>display: none</code> are also excluded — they're in the DOM, but they don't occupy space on screen.</p>
<p>Think of it this way:</p>
<ul>
<li><p><strong>DOM</strong> = the full structure, including invisible elements</p>
</li>
<li><p><strong>CSSOM</strong> = the style rules</p>
</li>
<li><p><strong>Render Tree</strong> = visible elements with styles attached</p>
</li>
</ul>
<p>The Render Tree is what the browser actually uses to figure out what to draw.</p>
<h2 id="heading-layout-reflow-where-does-everything-go">Layout (Reflow): Where Does Everything Go?</h2>
<p>Having a Render Tree tells the browser <em>what</em> to draw. But not <em>where</em>.</p>
<p>That's the <strong>Layout</strong> stage (also called Reflow). The browser walks the Render Tree and calculates the exact position and size of every element in pixels. This <code>&lt;h1&gt;</code> is 960px wide, starts at x=20, y=80. This <code>&lt;p&gt;</code> is 920px wide, starts at x=20, y=140. Percentage widths become pixels. Flexbox and grid calculations happen here. Text wrapping is figured out.</p>
<p>Layout is expensive. It runs again (hence "reflow") any time something changes element positions — a DOM element added, a CSS class toggled, an image that loads and shifts the page. Minimizing reflows is one of the most fundamental frontend performance optimisations.</p>
<h2 id="heading-painting-filling-in-the-pixels">Painting: Filling in the Pixels</h2>
<p>After layout, the browser knows where everything goes. Now it fills in the visuals — colors, text, shadows, borders, images. That's the <strong>Paint</strong> stage.</p>
<p>Modern browsers paint in layers. Animated or transformed elements get their own layers. These layers are then <strong>composited</strong> — combined by the GPU in the correct order — and displayed on screen.</p>
<p>This is why CSS <code>transform</code> animations are smoother than changing <code>top</code>/<code>left</code> — transforms happen at the compositing stage (GPU), not at the paint stage (CPU). Understanding this is the difference between 60fps animations and janky ones.</p>
<h2 id="heading-the-full-flow-start-to-finish">The Full Flow, Start to Finish</h2>
<p>Let me bring it together. Type a URL, press Enter. Here's what happens:</p>
<pre><code class="lang-plaintext">URL entered
  → DNS resolution (domain → IP address)
    → TCP connection opened
      → HTTP request sent
        → HTML received and parsed
          → DOM built
        → CSS fetched and parsed
          → CSSOM built
        → DOM + CSSOM → Render Tree
          → Layout (calculate positions)
            → Paint (fill pixels)
              → Composite (combine layers)
                → Webpage visible ✓
</code></pre>
<p>Every request. Every page. Every time. On a fast connection with a simple page, this entire pipeline can run in under a second.</p>
<h2 id="heading-where-javascript-fits-in">Where JavaScript Fits In</h2>
<p>JavaScript complicates the timeline — in an interesting way.</p>
<p>When the HTML parser encounters a <code>&lt;script&gt;</code> tag, it stops. It pauses HTML parsing, fetches the JavaScript file, executes it, then resumes parsing. This is why you've heard "put your scripts at the bottom of <code>&lt;body&gt;</code>" — placing scripts in <code>&lt;head&gt;</code> would block the entire page from rendering until the script downloads and runs.</p>
<p>JavaScript can modify the DOM. <code>document.createElement()</code>, <code>element.remove()</code>, <code>element.style.color = 'red'</code> — all of these change the Render Tree, which can trigger new Layout and Paint stages. This is called a <strong>reflow</strong> and <strong>repaint</strong>, and doing it excessively is one of the main causes of janky, slow websites.</p>
<p>The <code>async</code> and <code>defer</code> attributes on script tags exist precisely to give you control over when JavaScript runs relative to HTML parsing — so you can avoid blocking the render pipeline unnecessarily.</p>
<h2 id="heading-what-this-means-for-you-as-a-developer">What This Means for You as a Developer</h2>
<p>Understanding browser internals doesn't mean you need to memorize every specification. But it does change how you write code.</p>
<p>Knowing that CSS blocks rendering explains why you should keep stylesheets lean and load them early. Knowing that DOM manipulation triggers reflows explains why batching DOM changes is faster than making them one at a time. Knowing that JavaScript blocks HTML parsing explains <code>defer</code> and <code>async</code>. Knowing that painting happens in layers explains why CSS transforms are more performant than changing <code>top</code> and <code>left</code> for animations.</p>
<p>Every performance tip you'll ever read about frontend development — lazy loading, critical CSS, script deferral, avoiding layout thrashing — traces back to one or more of these pipeline stages.</p>
<p>You don't have to be a browser engineer to benefit from knowing this. You just have to understand the flow.</p>
<hr />
<p><em>Browsers are the most widely deployed, most used, and least understood piece of software in the world. Millions of people use them every day without ever thinking about DOM trees or render pipelines. But you're building things for browsers — and that's a good reason to understand what's happening on the other side of your code.</em></p>
]]></content:encoded></item><item><title><![CDATA[How DNS Resolution Actually Works: A Journey Through the Internet's Phonebook]]></title><description><![CDATA[There's a moment every developer hits where they stop taking DNS for granted. For me it was during my final year project when I changed an A record, refreshed the browser thirty seconds later, and nothing happened. I refreshed again. Still nothing. I...]]></description><link>https://blog.priyanshumaitra.dev/how-dns-resolution-actually-works-a-journey-through-the-internets-phonebook</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/how-dns-resolution-actually-works-a-journey-through-the-internets-phonebook</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[networking]]></category><category><![CDATA[computer networking]]></category><category><![CDATA[dns]]></category><category><![CDATA[#DNS Resolution]]></category><category><![CDATA[dns server]]></category><category><![CDATA[dns-records]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Sat, 24 Jan 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>There's a moment every developer hits where they stop taking DNS for granted. For me it was during my final year project when I changed an A record, refreshed the browser thirty seconds later, and nothing happened. I refreshed again. Still nothing. I spent two hours thinking my deployment was broken before someone told me DNS changes take time to propagate.</p>
<p>"What do you mean propagate? Where does it go?"</p>
<p>Nobody could explain it clearly. So I started digging — quite literally. There's a command called <code>dig</code> that shows you exactly how DNS resolution works, step by step, layer by layer. Once I understood what <code>dig</code> was telling me, DNS stopped being a black box entirely.</p>
<p>This blog walks through exactly what I learned: how DNS resolution actually works, and how to trace it yourself in your terminal.</p>
<h2 id="heading-what-dns-is-and-why-name-resolution-exists">What DNS Is (And Why Name Resolution Exists)</h2>
<p>Quick recap first. DNS stands for Domain Name System. It translates human-readable domain names like <a target="_blank" href="http://google.com"><code>google.com</code></a> into machine-readable IP addresses like <code>142.250.185.46</code>.</p>
<p>Computers don't understand <a target="_blank" href="http://google.com"><code>google.com</code></a>. They need an IP address to know where to send packets. But nobody wants to memorize <code>142.250.185.46</code>. DNS solves this by being the internet's phonebook — you look up a name, it gives you the number.</p>
<p>But here's what most explanations skip: DNS isn't a single server somewhere that knows everything. It's a hierarchy — a tree of servers distributed across the planet, each responsible for different parts of the domain namespace. When your browser needs to resolve <a target="_blank" href="http://google.com"><code>google.com</code></a>, it doesn't ask one server. It works through a chain.</p>
<p>Understanding that chain is what this entire blog is about.</p>
<h2 id="heading-meet-dig-the-dns-diagnostic-tool">Meet dig: The DNS Diagnostic Tool</h2>
<p><code>dig</code> stands for Domain Information Groper (yes, really). It's a command-line tool that lets you manually query DNS servers and see exactly what they respond with.</p>
<p>Developers and system administrators use <code>dig</code> for:</p>
<ul>
<li><p>Debugging DNS issues (why isn't my domain resolving?)</p>
</li>
<li><p>Verifying that DNS changes propagated correctly</p>
</li>
<li><p>Checking what nameservers are authoritative for a domain</p>
</li>
<li><p>Tracing the full DNS resolution path</p>
</li>
<li><p>Inspecting specific record types</p>
</li>
</ul>
<p>If you're on Linux or macOS, <code>dig</code> is almost certainly already installed. On Windows, you can use WSL or install it via BIND tools.</p>
<p>Basic syntax:</p>
<pre><code class="lang-bash">dig [domain] [record <span class="hljs-built_in">type</span>]
dig [domain] [record <span class="hljs-built_in">type</span>] @[nameserver]
</code></pre>
<p>We're going to use four specific <code>dig</code> commands that walk through the entire DNS resolution hierarchy, from the very top of the tree all the way down to the final answer.</p>
<h2 id="heading-layer-1-dig-ns-the-root-of-everything">Layer 1: dig . NS — The Root of Everything</h2>
<p>Let's start at the absolute beginning. Run this in your terminal:</p>
<pre><code class="lang-bash">dig . NS
</code></pre>
<p>That dot (<code>.</code>) represents the root of the DNS hierarchy. Every domain name actually ends with a dot — <a target="_blank" href="http://google.com"><code>google.com</code></a><code>.</code> — you just never type it. The root is above everything.</p>
<p>You'll get back something like:</p>
<pre><code class="lang-plaintext">;; ANSWER SECTION:
.   518400  IN  NS  a.root-servers.net.
.   518400  IN  NS  b.root-servers.net.
.   518400  IN  NS  c.root-servers.net.
.   518400  IN  NS  d.root-servers.net.
.   518400  IN  NS  e.root-servers.net.
.   518400  IN  NS  f.root-servers.net.
.   518400  IN  NS  g.root-servers.net.
.   518400  IN  NS  h.root-servers.net.
.   518400  IN  NS  i.root-servers.net.
.   518400  IN  NS  j.root-servers.net.
.   518400  IN  NS  k.root-servers.net.
.   518400  IN  NS  l.root-servers.net.
.   518400  IN  NS  m.root-servers.net.
</code></pre>
<p>Thirteen root name servers. <a target="_blank" href="http://a.root-servers.net"><code>a.root-servers.net</code></a> through <a target="_blank" href="http://m.root-servers.net"><code>m.root-servers.net</code></a>.</p>
<p>These are the starting point for all DNS resolution on the internet. They don't know where <a target="_blank" href="http://google.com"><code>google.com</code></a> is — but they know who to ask next. Root servers know which servers are responsible for each TLD (Top-Level Domain): <code>.com</code>, <code>.net</code>, <code>.org</code>, <code>.in</code>, <code>.dev</code>, and every other extension.</p>
<p>Think of root servers as the head office of a massive postal network. They don't know your specific delivery address. But they know which regional office handles your area, and they'll point you there.</p>
<p>There are only 13 logical root server addresses, but each one is actually a cluster of hundreds of physical machines distributed globally (using a technique called anycast). So "13 root servers" doesn't mean 13 machines — it means 13 address identifiers, each backed by hundreds of servers worldwide. The whole system is designed to never go down.</p>
<p>The <code>518400</code> number in that output is the TTL — Time To Live — in seconds (518400 seconds = 6 days). DNS responses can be cached for this duration before needing a fresh lookup.</p>
<h2 id="heading-layer-2-dig-com-ns-the-tld-layer">Layer 2: dig com NS — The TLD Layer</h2>
<p>Now let's go one level deeper. We know root servers handle the top of the tree. The next layer down is the TLD layer. Run:</p>
<pre><code class="lang-bash">dig com NS
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">;; ANSWER SECTION:
com.    172800  IN  NS  a.gtld-servers.net.
com.    172800  IN  NS  b.gtld-servers.net.
com.    172800  IN  NS  c.gtld-servers.net.
com.    172800  IN  NS  d.gtld-servers.net.
com.    172800  IN  NS  e.gtld-servers.net.
com.    172800  IN  NS  f.gtld-servers.net.
com.    172800  IN  NS  g.gtld-servers.net.
com.    172800  IN  NS  h.gtld-servers.net.
com.    172800  IN  NS  i.gtld-servers.net.
com.    172800  IN  NS  j.gtld-servers.net.
com.    172800  IN  NS  k.gtld-servers.net.
com.    172800  IN  NS  l.gtld-servers.net.
com.    172800  IN  NS  m.gtld-servers.net.
</code></pre>
<p>These are the <code>.com</code> TLD nameservers, operated by Verisign. GTLD stands for Generic Top-Level Domain. These servers know about every registered <code>.com</code> domain — not what IP they point to, but which nameservers are responsible for them.</p>
<p>When you register a domain like <a target="_blank" href="http://myportfolio.com"><code>myportfolio.com</code></a> with GoDaddy or Namecheap, your registrar tells these <code>.com</code> TLD servers: "Hey, <a target="_blank" href="http://myportfolio.com"><code>myportfolio.com</code></a> is managed by these nameservers." That's the NS record we talked about in the DNS records blog.</p>
<p>So the TLD servers answer a very specific question: "For this <code>.com</code> domain, who is the authoritative nameserver?" They don't give you IPs. They hand you off to the next layer.</p>
<p>Think of TLD servers as regional post offices. The head office (root) says "<code>.com</code>? Go to the regional office for America." That regional office knows which local branch office handles your specific street, but doesn't know your exact house number.</p>
<p>If you want to try the same for a different TLD:</p>
<pre><code class="lang-bash">dig <span class="hljs-keyword">in</span> NS     <span class="hljs-comment"># India's TLD servers</span>
dig dev NS    <span class="hljs-comment"># .dev TLD servers</span>
dig org NS    <span class="hljs-comment"># .org TLD servers</span>
</code></pre>
<p>Each TLD has its own set of authoritative nameservers managed by a different organization.</p>
<h2 id="heading-layer-3-dig-googlecomhttpgooglecom-ns-the-authoritative-layer">Layer 3: dig <a target="_blank" href="http://google.com">google.com</a> NS — The Authoritative Layer</h2>
<p>Now we're getting specific. Run:</p>
<pre><code class="lang-bash">dig google.com NS
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">;; ANSWER SECTION:
google.com.   345600  IN  NS  ns1.google.com.
google.com.   345600  IN  NS  ns2.google.com.
google.com.   345600  IN  NS  ns3.google.com.
google.com.   345600  IN  NS  ns4.google.com.
</code></pre>
<p>These are Google's own authoritative nameservers. These servers hold the actual DNS records for <a target="_blank" href="http://google.com"><code>google.com</code></a> — the A records, AAAA records, MX records, TXT records, everything.</p>
<p>The TLD servers for <code>.com</code> know that <a target="_blank" href="http://google.com"><code>google.com</code></a> is managed by <a target="_blank" href="http://ns1.google.com"><code>ns1.google.com</code></a> through <a target="_blank" href="http://ns4.google.com"><code>ns4.google.com</code></a>. So when someone needs to resolve <a target="_blank" href="http://google.com"><code>google.com</code></a>, the <code>.com</code> TLD servers say: "Go ask <a target="_blank" href="http://ns1.google.com">ns1.google.com</a>."</p>
<p>These authoritative nameservers are the final stop. They give a definitive answer. There's no "ask someone else" at this layer — the buck stops here.</p>
<p>For your own domain, these would be your hosting provider's nameservers, Cloudflare's nameservers, or whatever you configured as your NS records. When you set up a website and point your domain to Cloudflare, you're telling the TLD servers: "Cloudflare's nameservers are authoritative for this domain now."</p>
<p>The word "authoritative" is important. A nameserver is authoritative for a domain if it's the designated final source of truth for that domain's DNS records. All other DNS servers are just caching or relaying — only the authoritative server truly "owns" the answer.</p>
<h2 id="heading-layer-4-dig-googlecomhttpgooglecom-the-full-resolution">Layer 4: dig <a target="_blank" href="http://google.com">google.com</a> — The Full Resolution</h2>
<p>Now the full picture. Run:</p>
<pre><code class="lang-bash">dig google.com
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">;; QUESTION SECTION:
;google.com.        IN  A

;; ANSWER SECTION:
google.com.   300   IN  A  142.250.185.46

;; Query time: 12 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Sat Feb 15 10:23:44 IST 2026
;; MSG SIZE  rcvd: 55
</code></pre>
<p>There it is. <a target="_blank" href="http://google.com"><code>google.com</code></a> resolves to <code>142.250.185.46</code>. That's the IP address your browser will use to make an HTTP connection.</p>
<p>Let's break down the output fields:</p>
<p><code>QUESTION SECTION</code>: What you asked — the A record for <a target="_blank" href="http://google.com"><code>google.com</code></a>.</p>
<p><code>ANSWER SECTION</code>: The response — the IPv4 address.</p>
<p><code>300</code>: TTL of 300 seconds (5 minutes). After 5 minutes, this cached answer expires and needs a fresh lookup.</p>
<p><code>SERVER: 192.168.1.1</code>: This is your local recursive resolver — usually your router or ISP's DNS server. You didn't query the root servers directly. Your recursive resolver did all the legwork.</p>
<p>That last point is crucial to understand.</p>
<h2 id="heading-the-recursive-resolver-the-one-doing-all-the-work">The Recursive Resolver: The One Doing All the Work</h2>
<p>When you run <code>dig</code> <a target="_blank" href="http://google.com"><code>google.com</code></a>, your query goes to a recursive resolver — typically your ISP's DNS server or a public resolver like Google's <code>8.8.8.8</code> or Cloudflare's <code>1.1.1.1</code>.</p>
<p>The recursive resolver walks the hierarchy on your behalf:</p>
<ol>
<li><p>Queries a root nameserver: "Who handles <code>.com</code>?" → "Try <a target="_blank" href="http://a.gtld-servers.net"><code>a.gtld-servers.net</code></a>."</p>
</li>
<li><p>Queries the <code>.com</code> TLD server: "Who handles <a target="_blank" href="http://google.com"><code>google.com</code></a>?" → "Try <a target="_blank" href="http://ns1.google.com"><code>ns1.google.com</code></a>."</p>
</li>
<li><p>Queries Google's authoritative nameserver: "What's the A record for <a target="_blank" href="http://google.com"><code>google.com</code></a>?" → "<code>142.250.185.46</code>."</p>
</li>
<li><p>Returns the answer to you and caches it.</p>
</li>
</ol>
<p>Your browser sent one query. The resolver made three or four separate queries to servers across the internet. This entire process typically completes in under 50 milliseconds.</p>
<p>Every subsequent request for <a target="_blank" href="http://google.com"><code>google.com</code></a> within the TTL window (300 seconds here) comes from cache — no hierarchy walk needed.</p>
<p>To trace this manually without caching:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Step 1: Ask a root server about .com</span>
dig com NS @a.root-servers.net

<span class="hljs-comment"># Step 2: Ask a .com TLD server about google.com</span>
dig google.com NS @a.gtld-servers.net

<span class="hljs-comment"># Step 3: Ask Google's authoritative server for the A record</span>
dig google.com A @ns1.google.com
</code></pre>
<p>Each command is one hop. This is exactly what your recursive resolver does automatically, every time.</p>
<h2 id="heading-the-caching-layer-why-dns-changes-take-time">The Caching Layer: Why DNS Changes Take Time</h2>
<p>Remember my earlier frustration about DNS changes taking time? Now it makes sense.</p>
<p>Every DNS response includes a TTL. When a recursive resolver caches <a target="_blank" href="http://google.com"><code>google.com</code></a> <code>-&gt; 142.250.185.46</code> with a TTL of 300 seconds, it serves that cached answer to everyone who asks for the next 5 minutes — without going back to Google's nameservers.</p>
<p>If you change your A record from one IP to another, every cached copy of the old record across thousands of recursive resolvers worldwide has to expire first. Some resolvers cache aggressively. Some ISPs ignore TTLs entirely and cache for longer. This is why DNS propagation can take anywhere from a few minutes to 48 hours depending on your previous TTL setting.</p>
<p>Developer pro tip: If you know you're about to make a DNS change, lower your TTL to 300 seconds (5 minutes) a day before. Then make the change. Propagation will be much faster because resolvers cached your records with a short TTL. After the change stabilizes, raise it back to something like 86400 (24 hours) to reduce DNS lookup overhead.</p>
<h2 id="heading-connecting-this-to-real-browser-requests">Connecting This to Real Browser Requests</h2>
<p>When you type <a target="_blank" href="http://google.com"><code>google.com</code></a> and hit enter, your browser doesn't immediately call a DNS server. It checks its own cache first — browsers maintain their own DNS cache. On Chrome: <code>chrome://net-internals/#dns</code>.</p>
<p>If the browser cache misses, it asks the OS. Your OS has its own DNS cache too (<code>resolvectl statistics</code> on Linux). If that misses, the query goes to the recursive resolver configured on your network (<code>/etc/resolv.conf</code> on Linux).</p>
<p>Only if all caches miss does the full recursive resolution happen:</p>
<pre><code class="lang-plaintext">Browser cache
  -&gt; OS cache
    -&gt; Recursive resolver cache
      -&gt; Root -&gt; TLD -&gt; Authoritative
        -&gt; IP address returned
</code></pre>
<p>Most requests never make it past the third step. DNS is fast because caching is aggressive at every layer.</p>
<h2 id="heading-what-dig-teaches-you-that-documentation-doesnt">What dig Teaches You That Documentation Doesn't</h2>
<p>Running these four commands in order genuinely changed how I understood the internet. Not from reading — from seeing the actual responses:</p>
<pre><code class="lang-bash">dig . NS              <span class="hljs-comment"># Root servers: 13 addresses, each a global cluster</span>
dig com NS            <span class="hljs-comment"># TLD servers: Verisign manages .com</span>
dig google.com NS     <span class="hljs-comment"># Authoritative: Google manages google.com itself</span>
dig google.com        <span class="hljs-comment"># Final answer: IP address with TTL</span>
</code></pre>
<p>Each command revealed one layer. Together they showed me the complete hierarchy.</p>
<p>For any domain you're working with, swap out <a target="_blank" href="http://google.com"><code>google.com</code></a> for your own domain and run the same sequence. You'll see which nameservers are authoritative for your domain, what TTLs you've configured, which IP your A record points to, and whether your DNS changes have actually propagated to the authoritative layer.</p>
<p>And the next time a deployment breaks because of DNS, you'll know exactly where to look.</p>
<hr />
<p><em>DNS resolution is one of those foundational internet concepts that software engineers encounter constantly — domain setup, CDN configuration, service discovery, Kubernetes DNS — but rarely fully understand. The</em> <code>dig</code> command is your lens into all of it. Use it.</p>
]]></content:encoded></item><item><title><![CDATA[The Devices Behind the Internet: Modems, Routers, Switches, and More]]></title><description><![CDATA[In my third year, our professor asked the class a simple question: "When you deploy your application to a server, how does a user's request actually reach it?"
I said "the internet." He smiled and said, "Yes, but how?"
I had no answer. I'd been writi...]]></description><link>https://blog.priyanshumaitra.dev/the-devices-behind-the-internet-modems-routers-switches-and-more</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/the-devices-behind-the-internet-modems-routers-switches-and-more</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[dns]]></category><category><![CDATA[router]]></category><category><![CDATA[modem]]></category><category><![CDATA[Router-Switch]]></category><category><![CDATA[SWITCH]]></category><category><![CDATA[network]]></category><category><![CDATA[computer network]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Mon, 19 Jan 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>In my third year, our professor asked the class a simple question: "When you deploy your application to a server, how does a user's request actually reach it?"</p>
<p>I said "the internet." He smiled and said, "Yes, but how?"</p>
<p>I had no answer. I'd been writing code for two years, deploying things, using APIs — and I had zero idea what physically happened between someone clicking a button and my server receiving that request. I just assumed the internet was magic.</p>
<p>It's not magic. There's actual hardware involved, specific devices with specific jobs, and understanding them changed how I think about systems entirely. Whether you're a software engineer, a CS student, or someone who just wants to understand what all those blinking boxes in the IT room actually do — this one's for you.</p>
<h2 id="heading-the-big-picture-first">The Big Picture First</h2>
<p>Before getting into individual devices, let me give you the 30-second overview.</p>
<p>Think about a factory. Raw materials come in through a gate. They pass through security checks. Workers route materials to the right departments. Supervisors make sure no single department gets overwhelmed. Finished products leave through the same gate.</p>
<p>A network works similarly. Internet data comes in through one device, gets checked, gets directed, gets distributed to the right machines, and responses go back out the same way. Each device in that chain has one primary responsibility. That separation of responsibilities is what makes networks reliable.</p>
<p>Let's meet each device.</p>
<h2 id="heading-the-modem-your-gateway-to-the-internet">The Modem: Your Gateway to the Internet</h2>
<p>Modem stands for Modulator-Demodulator. But forget the acronym. Here's what it actually does.</p>
<p>Your internet service provider (Jio, Airtel, ACT — whoever sends you that monthly bill) delivers internet to your building through a physical cable, fiber line, or telephone wire. The signal traveling through that wire isn't something your laptop or router understands directly. It needs translation.</p>
<p>That's the modem's job. It translates signals from your ISP into a format your local network can use, and vice versa. It's the interpreter at the border.</p>
<p>Think of it like this: your ISP speaks French, your home network speaks English. The modem is the translator sitting at the border checkpoint, converting every message in both directions.</p>
<p>The modem gives you one IP address — the public IP your ISP assigns to you. Everything on your network shares this one public IP when talking to the outside world.</p>
<p>One important distinction: the modem only connects your network to the internet. It doesn't distribute that connection to multiple devices. That's the next device's job.</p>
<h2 id="heading-the-router-the-traffic-director">The Router: The Traffic Director</h2>
<p>Here's where most people get confused. Modems and routers look similar, they often come in the same box from ISPs, but they do completely different things.</p>
<p>The router's job is traffic direction — routing data packets to the right device within your network.</p>
<p>Imagine you live in an apartment building. All packages come to the building's front desk (the modem). But who delivers Package A to Flat 3B and Package B to Flat 7A? That's the router. It's the front desk manager who knows where everything needs to go.</p>
<p>When you have multiple devices — your phone, your laptop, your smart TV — they all connect to the router. The router assigns each device a private IP address (like 192.168.1.101, 192.168.1.102) and keeps a routing table tracking which device is which.</p>
<p>When a packet arrives from the internet destined for your laptop, the router checks its table: "192.168.1.102 — that's the laptop. Send it there." When your laptop makes a request, the router notes it, sends it out through the modem, and when the response arrives, delivers it back to the right device.</p>
<p>This translation between your private local IPs and the single public IP from your ISP is called NAT — Network Address Translation. Your router does this constantly, for every device, for every request.</p>
<p>This is also why when you're setting up a backend service and need to accept external traffic, you configure port forwarding on the router. You're literally telling it: "When traffic arrives on port 3000, send it to this specific device."</p>
<h2 id="heading-switch-vs-hub-how-local-networks-actually-work">Switch vs Hub: How Local Networks Actually Work</h2>
<p>Once you're inside a network — say, an office with 50 computers — you need a way to connect all those devices. That's where switches and hubs come in. And this distinction actually matters for performance.</p>
<p><strong>The Hub: The Loud Broadcaster</strong></p>
<p>A hub is the old, dumb way to connect devices. When Device A sends data to Device B through a hub, the hub does something baffling: it sends that data to every single device connected to it.</p>
<p>Every device receives the packet, checks if it's addressed to them, and discards it if it isn't. Device B gets the message. Devices C, D, E, F get noisy junk they have to throw away.</p>
<p>This is terrible for performance. As more devices connect, more unnecessary traffic floods the network. It's like a teacher who answers every student's question by announcing the answer to the entire school over the PA system, even when only one student asked.</p>
<p>Hubs are mostly obsolete now, but you'll still see them mentioned in networking courses.</p>
<p><strong>The Switch: The Smart Messenger</strong></p>
<p>A switch does the same job — connecting multiple devices on a local network — but it does it intelligently.</p>
<p>When Device A sends data to Device B, the switch reads the MAC address (a unique hardware identifier for each device's network card) and delivers the data only to Device B. No broadcasting. No noise. Just direct delivery.</p>
<p>The switch learns over time. The first time a device sends something, the switch notes its MAC address and which port it's connected to. After that, it knows exactly where to deliver future packets.</p>
<p>Think of a hub as a postal worker who makes photocopies of every letter and delivers them to every house on the street. A switch is a postal worker who actually reads the address and delivers to the correct house only.</p>
<p>In modern offices and data centers, everything uses switches. Hubs are genuinely antique at this point.</p>
<p><strong>Quick separation:</strong> Router connects different networks (your home to the internet). Switch connects devices within the same network (all the computers in your office).</p>
<h2 id="heading-the-firewall-the-security-checkpoint">The Firewall: The Security Checkpoint</h2>
<p>Every network needs a gatekeeper that decides what traffic is allowed in and what gets blocked. That's a firewall.</p>
<p>Think of it as the security guard at the entrance to a building. They check every person (packet) coming in, compare them against a list of rules, and decide: pass or block.</p>
<p>Firewalls work based on rules you define. Common rules:</p>
<ul>
<li><p>Block all incoming traffic on port 22 (SSH) except from specific IPs</p>
</li>
<li><p>Allow all outgoing traffic</p>
</li>
<li><p>Block traffic from known malicious IP ranges</p>
</li>
<li><p>Only allow HTTP (port 80) and HTTPS (port 443) from outside</p>
</li>
</ul>
<p>When I first deployed a backend application on a cloud VM, I couldn't access it from my browser even though the server was running. Turns out the cloud provider's firewall was blocking port 3000. I hadn't opened that port in the security group rules.</p>
<p>Security groups in AWS, firewall rules in GCP, network security groups in Azure — these are all software-defined firewalls. Same concept, different interfaces.</p>
<p>Hardware firewalls sit physically between your router and internal network in enterprise setups. Software firewalls run on individual machines (like Windows Defender's firewall or <code>ufw</code> on Ubuntu). Both do the same job: enforce rules about what traffic is permitted.</p>
<p>A firewall doesn't just check source and destination IPs. Sophisticated firewalls do deep packet inspection — actually examining the content of traffic to detect malware, unauthorized data exfiltration, or attack patterns.</p>
<p>For any application you deploy publicly, firewall configuration isn't optional. It's the first line of defence.</p>
<h2 id="heading-the-load-balancer-the-traffic-distributor">The Load Balancer: The Traffic Distributor</h2>
<p>Here's where we get into territory that's directly relevant to backend engineering and production systems.</p>
<p>Imagine your API server handles 1000 requests per minute comfortably. But you launch a feature that goes viral and suddenly you're getting 10,000 requests per minute. One server can't handle that. So you spin up five servers.</p>
<p>But how do users know which server to talk to? You can't give them five different IP addresses. You need something that sits in front of all five servers, receives all incoming traffic, and distributes it across them.</p>
<p>That's a load balancer.</p>
<p>It's like a receptionist at a busy company. You call the main number (the load balancer's IP). The receptionist doesn't handle your request — they transfer you to the first available representative (server). You never know which representative you got. From your perspective, you just called the company.</p>
<p>Load balancers use different algorithms to distribute traffic:</p>
<p><strong>Round Robin</strong>: Request 1 goes to Server A, Request 2 to Server B, Request 3 to Server C, Request 4 back to Server A. Simple rotation.</p>
<p><strong>Least Connections</strong>: Send each new request to whichever server currently has the fewest active connections. Smart when requests have varying processing times.</p>
<p><strong>IP Hash</strong>: Same client IP always goes to the same server. Useful when you need session persistence — the user stays connected to the same backend throughout their session.</p>
<p>Load balancers also do health checks. Every few seconds, they ping each server: "Are you alive?" If a server stops responding, the load balancer stops sending traffic to it and routes everything to the healthy servers. No manual intervention needed.</p>
<p>This is why Nginx and HAProxy are so common in production setups. They're software load balancers handling traffic distribution at scale. AWS ALB (Application Load Balancer), GCP's Cloud Load Balancing — same idea, managed by the cloud provider.</p>
<h2 id="heading-how-they-all-work-together">How They All Work Together</h2>
<p>Let me walk you through what happens when a user opens your web application. Every step involves one of these devices.</p>
<p><strong>User types your-app.com and hits Enter.</strong></p>
<ol>
<li><p>Their DNS lookup resolves your domain to a public IP. That IP belongs to your load balancer.</p>
</li>
<li><p>The request travels across the internet and arrives at your <strong>modem</strong> — the entry point into your infrastructure's network.</p>
</li>
<li><p>The <strong>router</strong> receives the packet from the modem and directs it internally toward the load balancer based on its routing table.</p>
</li>
<li><p>The <strong>firewall</strong> inspects the packet. Is it coming from a blocked IP? Is it hitting an allowed port? Is it a valid HTTP request? Rules pass. Traffic gets through.</p>
</li>
<li><p>The <strong>load balancer</strong> receives the request. Checks which backend server is least busy. Forwards the request to Server 2 of your backend cluster.</p>
</li>
<li><p>The <strong>switch</strong> in your data center or rack handles the physical delivery of that packet from the load balancer to Server 2 — finding the right machine by MAC address.</p>
</li>
<li><p>Server 2 processes the request, queries the database, builds a response, and sends it back up the same chain.</p>
</li>
<li><p>The response goes back through the switch, through the load balancer, through the firewall (outbound rules check), through the router, through the modem, and out to the user.</p>
</li>
</ol>
<p>All of that happens in milliseconds.</p>
<h2 id="heading-why-software-engineers-should-care-about-hardware">Why Software Engineers Should Care About Hardware</h2>
<p>I get it. You write code. You don't configure Cisco switches. But here's the thing — understanding this stack makes you a better engineer, not just someone who can answer networking questions in interviews.</p>
<p>When your API is slow, you'll know whether to look at application code, check if the load balancer is misconfigured, or verify that firewall rules aren't throttling traffic. When a production deployment goes wrong and traffic isn't reaching your new servers, you'll know to check if the load balancer's health checks are passing before you start digging through application logs.</p>
<p>When a security incident happens, you'll understand what the firewall logs are telling you.</p>
<p>These aren't abstract concepts. Every production backend system runs on top of this stack. Cloud providers abstract most of it behind managed services and dashboards, but the same devices, the same responsibilities, the same traffic flow — it's all still there.</p>
<p>Understanding the hardware helps you reason about the system as a whole. And the engineers who can do that — who see beyond just their service to the full stack — are the ones who build systems that actually hold up under real-world conditions.</p>
<hr />
<p><em>This is part of my ongoing series on how the internet and backend systems actually work at a foundational level. If you're a developer who wants to go beyond "it just works" to actually understanding the infrastructure underneath your code, this series is for you.</em></p>
]]></content:encoded></item><item><title><![CDATA[How Does Your Browser Know Where a Website Lives?]]></title><description><![CDATA[I'll never forget buying my first domain. 2021, lockdown. Built a portfolio website, bought "priyanshumaitra.dev", pointed it to my hosting, and... nothing worked.
I stared at my screen for an hour. Domain: mine. Website: ready. Why wasn't it showing...]]></description><link>https://blog.priyanshumaitra.dev/understanding-dns-record-types</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/understanding-dns-record-types</guid><category><![CDATA[dns]]></category><category><![CDATA[dns-records]]></category><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[NsRecords]]></category><category><![CDATA[cname records]]></category><category><![CDATA[AAAA Record ]]></category><category><![CDATA[MX Record]]></category><category><![CDATA[TXT Record]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Sun, 18 Jan 2026 18:30:00 GMT</pubDate><content:encoded><![CDATA[<p>I'll never forget buying my first domain. 2021, lockdown. Built a portfolio website, bought "priyanshumaitra.dev", pointed it to my hosting, and... nothing worked.</p>
<p>I stared at my screen for an hour. Domain: mine. Website: ready. Why wasn't it showing up?</p>
<p>I hadn't set up DNS records. Didn't even know what they were. Thought buying a domain and having a website was enough. It's not.</p>
<p>Let me save you that confusion.</p>
<h2 id="heading-the-simple-question-how-does-a-browser-find-your-website">The Simple Question: How Does a Browser Find Your Website?</h2>
<p>Think about this: you type "google.com" into your browser and hit enter. Within milliseconds, you're looking at Google's homepage. But here's the thing – computers don't understand "google.com". They work with IP addresses like <code>142.250.185.46</code>.</p>
<p>So how does your browser translate "google.com" into that number?</p>
<p>That's where DNS comes in. DNS stands for Domain Name System, but forget the technical term. Think of it as the internet's phonebook.</p>
<p>You know how you save contacts in your phone? Instead of remembering that your friend's number is +91-9876543210, you just save it as "Priyanshu" and tap to call. DNS does the same thing for websites. It translates human-friendly names like "google.com" into computer-friendly numbers like <code>142.250.185.46</code>.</p>
<p>Without DNS, you'd have to memorize IP addresses for every website you visit. Imagine typing <code>172.217.160.142</code> every time you wanted to check Facebook. Nobody's doing that.</p>
<h2 id="heading-why-dns-records-exist">Why DNS Records Exist</h2>
<p>Here's where it gets interesting. DNS isn't just "domain name = IP address". It's more complex because the internet needs more information than just where your website lives.</p>
<p>Think about a business. You don't just need their address. You might also need:</p>
<ul>
<li><p>Who owns the building (NS records)</p>
</li>
<li><p>The street address (A records)</p>
</li>
<li><p>Alternative addresses (AAAA records)</p>
</li>
<li><p>Nicknames for the location (CNAME records)</p>
</li>
<li><p>Where to send mail (MX records)</p>
</li>
<li><p>Additional business info (TXT records)</p>
</li>
</ul>
<p>DNS records are different types of information about your domain, stored in a system that the whole internet can access. Each record type serves a specific purpose.</p>
<p>When I finally understood this, everything clicked. Let me break down each record type.</p>
<h2 id="heading-ns-records-whos-in-charge">NS Records: Who's In Charge?</h2>
<p>NS stands for Name Server. This tells the internet: "Who manages this domain's DNS records?"</p>
<p>Think of it like property ownership. NS record points to who manages the property, not where it is.</p>
<p>When you buy a domain, registrars set their name servers:</p>
<pre><code class="lang-plaintext">ns1.godaddy.com
ns2.godaddy.com
</code></pre>
<p>When I moved to Cloudflare, I changed NS records to:</p>
<pre><code class="lang-plaintext">brad.ns.cloudflare.com
elsa.ns.cloudflare.com
</code></pre>
<p>Now Cloudflare manages all my DNS. The NS record says, "For questions about myportfolio.tech, ask Cloudflare."</p>
<p>Most beginners don't touch NS records unless changing DNS providers.</p>
<h2 id="heading-a-records-the-main-address">A Records: The Main Address</h2>
<p>This is the big one. The A record (Address record) maps your domain name to an IPv4 address.</p>
<p>When someone types "myportfolio.tech" into their browser, the A record says: "That website lives at 192.0.2.1" (example IP).</p>
<p>It's literally that simple:</p>
<pre><code class="lang-plaintext">myportfolio.tech  -&gt;  192.0.2.1
</code></pre>
<p>You can also create subdomain A records:</p>
<pre><code class="lang-plaintext">blog.myportfolio.tech  -&gt;  198.51.100.5
api.myportfolio.tech   -&gt;  203.0.113.10
</code></pre>
<p>Each subdomain can point to a different server. My main site might be on one server, my blog on another, my API on a third. A records make this possible.</p>
<p>The "A" stands for "Address", but specifically IPv4 addresses (the familiar 4-number format like <code>192.168.1.1</code>).</p>
<h2 id="heading-aaaa-records-the-future-address">AAAA Records: The Future Address</h2>
<p>AAAA records do the same as A records, but for IPv6 addresses.</p>
<p>IPv6 looks like: <code>2001:0db8:85a3:0000:0000:8a2e:0370:7334</code>. Longer, uglier, but necessary because we're running out of IPv4 addresses.</p>
<p>Most websites have both:</p>
<pre><code class="lang-plaintext">myportfolio.tech  -&gt;  192.0.2.1      (A - IPv4)
myportfolio.tech  -&gt;  2001:db8::1    (AAAA - IPv6)
</code></pre>
<p>Devices use whichever format they support. Modern devices prefer IPv6, fall back to IPv4.</p>
<p>When I started, I only set up A records. Hosting providers usually handle AAAA automatically. Unless managing your own servers, you might not need to configure these manually.</p>
<h2 id="heading-cname-records-the-alias">CNAME Records: The Alias</h2>
<p>CNAME stands for Canonical Name. It's an alias - one name pointing to another name.</p>
<p>Here's a real scenario I faced: I had my website hosted on GitHub Pages. GitHub told me to point my domain to <code>username.github.io</code>. But I wanted people to access it via <code>www.myportfolio.tech</code>.</p>
<p>I couldn't create an A record because GitHub Pages doesn't give you a fixed IP address. The IP might change. So I used a CNAME:</p>
<pre><code class="lang-plaintext">www.myportfolio.tech  -&gt;  username.github.io
</code></pre>
<p>Now when someone visits <code>www.myportfolio.tech</code>, DNS says "that's actually an alias for <code>username.github.io</code>" and looks up that address instead.</p>
<p><strong>Here's the key difference between A and CNAME:</strong></p>
<ul>
<li><p><strong>A record</strong>: Points directly to an IP address</p>
</li>
<li><p><strong>CNAME</strong>: Points to another domain name, which then resolves to an IP</p>
</li>
</ul>
<p>Think of it like this: An A record is a street address. A CNAME is "same address as John's place" - you need to look up John's address to find it.</p>
<p><strong>Important rule:</strong> You can't use CNAME for your root domain (myportfolio.tech). Only subdomains (www.myportfolio.tech, blog.myportfolio.tech). This confused me for days when I was starting out.</p>
<h2 id="heading-mx-records-how-email-finds-you">MX Records: How Email Finds You</h2>
<p>MX stands for Mail Exchange. These tell the internet where to send emails for your domain.</p>
<p>When someone emails <code>contact@myportfolio.tech</code>, their email server checks your MX records.</p>
<pre><code class="lang-plaintext">myportfolio.tech  MX  10  mail.google.com
</code></pre>
<p>The number (10) is priority. Lower = higher priority. Multiple mail servers? Email tries the lowest number first.</p>
<p>I use Google Workspace, so my MX records point to Google:</p>
<pre><code class="lang-plaintext">myportfolio.tech  MX  1   aspmx.l.google.com
myportfolio.tech  MX  5   alt1.aspmx.l.google.com
</code></pre>
<p>If the first server is down, email tries the second.</p>
<p><strong>Important:</strong> MX records are only for email. Your website can be down and email still works (and vice versa).</p>
<h2 id="heading-txt-records-the-information-board">TXT Records: The Information Board</h2>
<p>TXT records store text information. Like a bulletin board for notes that other services can read.</p>
<p>Common uses:</p>
<p><strong>Domain verification:</strong> Proving you own the domain:</p>
<pre><code class="lang-plaintext">myportfolio.tech  TXT  "google-site-verification=abc123"
</code></pre>
<p><strong>Email security (SPF):</strong> Which servers can send email from your domain:</p>
<pre><code class="lang-plaintext">myportfolio.tech  TXT  "v=spf1 include:_spf.google.com ~all"
</code></pre>
<p>Prevents spammers from forging emails from your domain.</p>
<p><strong>DKIM and DMARC:</strong> More email authentication, stored as TXT records.</p>
<p>You won't create many TXT records yourself. Services like Google or Cloudflare give you exact TXT records to add.</p>
<h2 id="heading-how-it-all-works-together">How It All Works Together</h2>
<p>Let's see how these records work for <code>priyanshumaitra.dev</code>:</p>
<p><strong>Website visit:</strong></p>
<ol>
<li><p>Browser asks: "Where is myportfolio.tech?"</p>
</li>
<li><p>DNS checks NS: "Cloudflare manages this."</p>
</li>
<li><p>Asks Cloudflare: "What's the A record?"</p>
</li>
<li><p>Cloudflare: "192.0.2.1"</p>
</li>
<li><p>Browser connects and loads website.</p>
</li>
</ol>
<p><strong>Email:</strong></p>
<ol>
<li><p>Email server: "Where does mail for myportfolio.tech go?"</p>
</li>
<li><p>DNS checks MX: "Send to mail.google.com"</p>
</li>
<li><p>Email delivered to Google's servers.</p>
</li>
</ol>
<p>Google checks TXT records for SPF, DKIM verification.</p>
<p><strong>Subdomain:</strong></p>
<ol>
<li><p>Visit <code>blog.priyanshumaitra.dev</code></p>
</li>
<li><p>DNS finds A record at 198.51.100.5 (different server)</p>
</li>
<li><p>Or finds CNAME pointing to <a target="_blank" href="https://hashnode.com/@priyanshumaitra">hashnode.com/@priyanshumaitra</a></p>
</li>
</ol>
<p>All records work simultaneously, independently, serving different purposes.</p>
<h2 id="heading-common-confusions-i-had-and-you-might-too">Common Confusions I Had (And You Might Too)</h2>
<p><strong>"Can I use both A and CNAME for the same domain?"</strong> No. Just pick one. Either point directly to an IP (A record) or point to another domain (CNAME). Not both.</p>
<p><strong>"What's the difference between NS and MX?"</strong> NS says who manages ALL your DNS records. MX says where EMAIL goes. Completely different jobs.</p>
<p><strong>"Do I need AAAA records?"</strong> Not mandatory, but recommended. Your host probably sets them up automatically.</p>
<p><strong>"Why can't I CNAME my root domain?"</strong> Technical reasons involving DNS specifications. Use A records for root domains, CNAME for subdomains.</p>
<p><strong>"How long do DNS changes take?"</strong> Usually minutes, sometimes hours. It's called DNS propagation. Different servers update at different speeds.</p>
<h2 id="heading-what-i-wish-i-knew-earlier">What I Wish I Knew Earlier</h2>
<p>When I bought my first domain, I thought: Buy domain → Point to website → Done.</p>
<p>Reality:</p>
<ol>
<li><p>Buy domain</p>
</li>
<li><p>Set NS records (usually automatic)</p>
</li>
<li><p>Set A record to server IP</p>
</li>
<li><p>Set MX records for email</p>
</li>
<li><p>Add TXT records for verification</p>
</li>
<li><p>Maybe CNAME for www subdomain</p>
</li>
<li><p>Wait for DNS propagation</p>
</li>
<li><p>Troubleshoot</p>
</li>
<li><p>Fix the typo in your IP</p>
</li>
<li><p>Wait again</p>
</li>
</ol>
<p>Understanding DNS records saves massive time. Now when something breaks, I check DNS first.</p>
<h2 id="heading-the-bigger-picture">The Bigger Picture</h2>
<p>DNS records might seem technical and boring, but they're the foundation of how the internet works. Every website you visit, every email you send, every API you call - DNS is working behind the scenes.</p>
<p>You don't need to be a DNS expert to build websites. Most hosting providers handle the basics automatically. But understanding these records helps you:</p>
<ul>
<li><p>Set up custom domains confidently</p>
</li>
<li><p>Troubleshoot when things break</p>
</li>
<li><p>Migrate between hosting providers</p>
</li>
<li><p>Configure custom email addresses</p>
</li>
<li><p>Understand why changes take time to propagate</p>
</li>
</ul>
<p>That first domain I bought? Once I learned about DNS records, I had it working in 20 minutes. The knowledge has saved me countless hours since.</p>
<p>So next time you type a URL and hit enter, remember: there's a whole system of records working together to get you where you need to go. And now you know how it works.</p>
<hr />
<p><em>DNS is one of those things that seems complicated until it clicks. Then it's just addresses, aliases, and instructions. If you're setting up your first domain, take it slow, one record at a time. You'll get it.</em></p>
]]></content:encoded></item><item><title><![CDATA[Unlocking Git: Demystifying the .git Folder and Its Inner Workings]]></title><description><![CDATA[You know that moment when you break something and suddenly everything makes sense? That was me with the .git folder.
It was 2022. I'd been using Git for about a year, felt comfortable with the basics. Then while cleaning my project, I saw this .git f...]]></description><link>https://blog.priyanshumaitra.dev/unlocking-git-demystifying-the-git-folder-and-its-inner-workings</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/unlocking-git-demystifying-the-git-folder-and-its-inner-workings</guid><category><![CDATA[Git]]></category><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[vcs]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Sat, 17 Jan 2026 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769800369891/175c0a39-962b-479c-8a4f-98b3062d3f46.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You know that moment when you break something and suddenly everything makes sense? That was me with the <code>.git</code> folder.</p>
<p>It was 2022. I'd been using Git for about a year, felt comfortable with the basics. Then while cleaning my project, I saw this <code>.git</code> folder taking up 200MB. "Hidden folder? Probably just cache," I thought. So I deleted it.</p>
<p>My entire Git history vanished. Every commit, every branch, everything – gone. The files were still there, but Git acted like they never existed. That's when it hit me: Git isn't magic. It's just clever file management. And everything lives in that <code>.git</code> folder I just nuked.</p>
<p>Let me show you what I learned the hard way.</p>
<h2 id="heading-understanding-the-git-folder-gits-entire-universe">Understanding the .git Folder: Git's Entire Universe</h2>
<p>When you run <code>git init</code>, Git creates a <code>.git</code> folder in your project directory. That's literally all it takes for your folder to become a Git repository. This single hidden folder is Git's entire universe – every commit, every branch, every piece of history lives here.</p>
<p>Delete <code>.git</code>? You delete Git. The folder stops being a repository. Your files stay, but Git forgets they ever existed.</p>
<p>Let's peek inside:</p>
<pre><code class="lang-bash">ls -la .git/
</code></pre>
<p>You'll see:</p>
<pre><code class="lang-plaintext">HEAD          → Points to your current location
config        → Repository settings
objects/      → Where all your data lives
refs/         → Branch and tag pointers
index         → The staging area
hooks/        → Automation scripts
</code></pre>
<p>Everything Git knows about your project is in these files and folders. No external database, no hidden cloud storage. Just files on your disk.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769786586560/e5b1d1b3-634c-4f88-9c0a-c73b3af024a8.png" alt="Diagram of a .git directory structure showing: HEAD pointing to the current branch, config for repository settings, refs for branch and tag references, objects for commits and data, and logs for operation history." class="image--center mx-auto" /></p>
<h2 id="heading-how-git-actually-works-its-all-about-hashes">How Git Actually Works: It's All About Hashes</h2>
<p>Here's the core concept that changed everything for me: Git doesn't store files by name. It stores them by content.</p>
<p>When you add a file to Git, it does this:</p>
<ol>
<li><p>Reads the file content</p>
</li>
<li><p>Calculates a SHA-1 hash of that content</p>
</li>
<li><p>Compresses the content</p>
</li>
<li><p>Stores it using the hash as the filename</p>
</li>
</ol>
<p>Let's say you have a file <code>hello.txt</code> with "Hello World" inside. Git calculates its hash: <code>557db03de997c86a4a028e1ebd3a1ceb225be238</code>. It then stores the compressed content at:</p>
<pre><code class="lang-plaintext">.git/objects/55/7db03de997c86a4a028e1ebd3a1ceb225be238
</code></pre>
<p>The beautiful part? Same content = same hash = stored only once. Have the same file in 50 commits? Git stores it once. This is how Git stays efficient even with massive histories.</p>
<p>The hash also guarantees integrity. Change even one character, and you get a completely different hash. Git instantly knows if data got corrupted.</p>
<h2 id="heading-git-objects-the-building-blocks">Git Objects: The Building Blocks</h2>
<p>Git stores everything as objects. Three types: blobs, trees, and commits.</p>
<p><strong>Blob Objects</strong>: Your file contents. No filename, no structure – just raw content, compressed and hashed. When you <code>git add readme.md</code>, Git creates a blob with that file's content.</p>
<p><strong>Tree Objects</strong>: Your directory structure. Contains blob references (files), other trees (subdirectories), filenames and permissions. Like a folder inventory.</p>
<p><strong>Commit Objects</strong>: Your snapshots. Contains a tree pointer, parent commit pointer, author info, and message. The commit doesn't hold files – it points to them via the tree.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769786747858/30cc262f-1693-4010-ae32-dfeb6161bc90.png" alt="Diagram illustrating the relationship between commits, trees, and blobs in a version control system. Commit 1 links to Tree 1, which connects to several blobs and another tree. Commit 2 links to Tree 2, and Commit 3 links to Tree 3, both with similar structures." class="image--center mx-auto" /></p>
<pre><code class="lang-bash">git cat-file -p HEAD
</code></pre>
<p>Shows:</p>
<pre><code class="lang-plaintext">tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
parent 8f3d3e8a9c7b4e5f6a2d1c3b4a5e6f7a8b9c0d1e
author Your Name &lt;you@example.com&gt; 1638360000 +0530

Add login feature
</code></pre>
<p>Each commit knows its parent, creating a chain – your project's history.</p>
<h2 id="heading-what-happens-during-git-add-building-the-index">What Happens During git add: Building the Index</h2>
<p>The staging area confused me for months. Then I understood what <code>git add</code> actually does.</p>
<p>When you run <code>git add app.js</code>:</p>
<ol>
<li><p>Git reads your file content</p>
</li>
<li><p>Creates a blob object</p>
</li>
<li><p>Calculates its hash</p>
</li>
<li><p>Stores it in <code>.git/objects/</code></p>
</li>
<li><p>Updates <code>.git/index</code> with this blob's hash</p>
</li>
</ol>
<p>The index is a binary file mapping filenames to blob hashes. It's a draft of your next commit. Modified five files? Add three, commit them. The staging area gives you this control.</p>
<h2 id="heading-what-happens-during-git-commit-saving-the-snapshot">What Happens During git commit: Saving the Snapshot</h2>
<p>When you run <code>git commit -m "Add feature"</code>:</p>
<ol>
<li><p>Reads the index to see what's staged</p>
</li>
<li><p>Creates tree objects for your directory structure</p>
</li>
<li><p>Creates a commit object with tree reference, parent commit, author info, and message</p>
</li>
<li><p>Stores the commit in <code>.git/objects/</code></p>
</li>
<li><p>Updates current branch reference to point to new commit</p>
</li>
</ol>
<p>That last step is key. Branches are just pointers to commits. When you're on <code>main</code>, there's a file at <code>.git/refs/heads/main</code> with a commit hash. Committing updates this file.</p>
<pre><code class="lang-bash">cat .git/refs/heads/main
8f3d3e8a9c7b4e5f6a2d1c3b4a5e6f7a8b9c0d1e
</code></pre>
<p>That's your entire branch – a 40-character hash in a text file.</p>
<h2 id="heading-how-git-tracks-changes-it-doesnt">How Git Tracks Changes: It Doesn't</h2>
<p>Here's something that blew my mind: Git doesn't track changes. It tracks snapshots.</p>
<p>When you commit, Git doesn't store "changed line 15 in app.js". It stores a complete snapshot of your entire project at that point in time. Every commit is a full project snapshot.</p>
<p>"Wait," I thought when I learned this, "doesn't that waste tons of space?"</p>
<p>No, because of content-addressing. Remember, Git stores objects by their content hash. If a file doesn't change between commits, both commits point to the same blob object. No duplication.</p>
<p>You have 100 files, change one, and commit? Git creates:</p>
<ul>
<li><p>One new blob (the changed file)</p>
</li>
<li><p>New tree objects for affected directories</p>
</li>
<li><p>One new commit object</p>
</li>
<li><p>The other 99 files? Same blobs, same hashes, already in <code>.git/objects/</code></p>
</li>
</ul>
<p>When you run <code>git diff</code>, Git compares two snapshots and shows you the differences. But those differences aren't stored – they're calculated on the fly.</p>
<p>This is why Git can show you any version of your project instantly. It's not replaying changes – it's checking out a snapshot.</p>
<h2 id="heading-branches-are-just-pointers">Branches Are Just Pointers</h2>
<p>A branch is a text file containing a commit hash. That's it.</p>
<pre><code class="lang-bash">git branch feature-login
</code></pre>
<p>This creates <code>.git/refs/heads/feature-login</code> with the current commit's hash. No files copied. Just a 41-byte text file.</p>
<p>Switching branches? Git updates HEAD, reads the commit hash, updates your working directory. Instant and lightweight.</p>
<p>HEAD is also a pointer:</p>
<pre><code class="lang-bash">cat .git/HEAD
ref: refs/heads/main
</code></pre>
<p>When you commit, Git follows HEAD to the branch, creates the new commit with the old commit as parent, and updates the branch reference.</p>
<h2 id="heading-building-your-mental-model">Building Your Mental Model</h2>
<p>Understanding Git internals gave me a clear mental model:</p>
<p><strong>Working directory</strong>: Your workspace for editing files.</p>
<p><strong>Index</strong> (<code>.git/index</code>): Your draft. <code>git add</code> moves changes here.</p>
<p><strong>Repository</strong> (<code>.git/objects/</code>): Published work. <code>git commit</code> makes drafts permanent.</p>
<p><strong>Branches</strong>: Bookmarks pointing to commits. Cheap and disposable.</p>
<p><strong>Commits</strong>: Snapshots forming a chain through parent references.</p>
<p>Everything is in <code>.git/</code>. Nothing's in the cloud unless you push. No magic – just files and pointers.</p>
<h2 id="heading-why-this-matters">Why This Matters</h2>
<p>Understanding that branches are pointers removes the fear of branching. They cost nothing.</p>
<p>Understanding commits as snapshots explains why jumping between commits is instant.</p>
<p>Understanding the staging area shows it's giving you control, not adding friction.</p>
<p>Understanding object storage explains why Git excels with code (small text files) but struggles with videos or binaries (huge blobs).</p>
<p>And when things break, you know your data's in <code>.git/objects/</code>, recoverable with <code>git reflog</code>.</p>
<h2 id="heading-the-recovery-story">The Recovery Story</h2>
<p>Remember when I deleted <code>.git</code>? That was my personal project. Annoying but recoverable from my last push.</p>
<p>But months later, a teammate ran a bad rebase that scrambled our branch. Everyone panicked. We thought days of work were lost.</p>
<p>I knew better. Everything was in <code>.git/objects/</code>. I used <code>git reflog</code> to find where HEAD was before the bad rebase:</p>
<pre><code class="lang-bash">git reflog
</code></pre>
<p>Found the commit hash we needed, created a new branch pointing to it:</p>
<pre><code class="lang-bash">git branch recovery abc1234
</code></pre>
<p>Everything recovered in two minutes. My teammates thought I was a wizard. I just understood the model.</p>
<h2 id="heading-the-git-folder-is-everything">The .git Folder Is Everything</h2>
<p>These days, I treat <code>.git/</code> as sacred. Project files? Those are just the current state. I can regenerate them from any commit. But <code>.git/</code>? That's the entire history. Every commit, every branch, everything.</p>
<p>Some people exclude <code>.git/</code> from backups to save space. I do the opposite. I'll lose working directory over <code>.git/</code> any day. With the repository, I can restore anything. Without it, I have nothing.</p>
<p>And I never delete hidden folders to "save space" anymore. Learned that lesson well.</p>
<hr />
<p><em>Understanding Git's internals transformed it from a tool I feared breaking to a system I could reason about. Next time you run a Git command, picture what's happening in</em> <code>.git/</code>. It makes everything make sense. Git isn't magic – it's just clever file management with pointers and hashes. And once you get that, you get Git.</p>
]]></content:encoded></item><item><title><![CDATA[The Pendrive Problem: Why I Couldn't Live Without Version Control Anymore]]></title><description><![CDATA[Remember carrying your entire project on a pendrive? That tiny USB stick hanging from your keys like it held the secrets to the universe? Yeah, I do. Looking back, I don't know how I survived.
First year of my diploma, 2020. My team was building a li...]]></description><link>https://blog.priyanshumaitra.dev/version-control-system-git-github</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/version-control-system-git-github</guid><category><![CDATA[Git]]></category><category><![CDATA[version control]]></category><category><![CDATA[version control systems]]></category><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[Developer Tools]]></category><category><![CDATA[vcs]]></category><category><![CDATA[GitHub]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Fri, 16 Jan 2026 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769777580687/0ec6ffed-a51e-440f-8c04-70289a8dd9c1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Remember carrying your entire project on a pendrive? That tiny USB stick hanging from your keys like it held the secrets to the universe? Yeah, I do. Looking back, I don't know how I survived.</p>
<p>First year of my diploma, 2020. My team was building a library management system. We had a week, started two days before the deadline(classic). Our workflow: work on my laptop, save to pendrive, walk to my teammate's place, plug it in, he continues. Simple, right? Wrong.</p>
<h2 id="heading-the-pendrive-chaos">The Pendrive Chaos</h2>
<p>One evening, I was working on the book-issue module while my teammate was supposedly fixing the search functionality. I finished my part, saved it to the pendrive, and went to sleep feeling accomplished. The next morning, I plug in the pendrive, and boom, half my code is gone. Turns out, my teammate had worked on an older version from his laptop and overwrote my changes when he saved to the pendrive.</p>
<p>We had this brilliant naming convention too:</p>
<pre><code class="lang-plaintext">library_management.cpp
library_management_final.cpp
library_management_final_v2.cpp
library_management_actual_final.cpp
library_management_THIS_IS_THE_ONE.cpp
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769776923084/2779288a-6564-4dbf-bc84-e2ad0d3188eb.png" alt="Comparison diagram of pendrive-based workflow and version control workflow. Left side shows a pendrive transferring files between laptops, leading to multiple modified files. Right side illustrates a centralized version control system with computers pushing and pulling changes, involving users John and Bob." class="image--center mx-auto" /></p>
<p>Sound familiar? I bet it does. We all did this. We thought we were being smart by keeping backups. But let me ask you, which one was actually the latest? Which version had the bug fix for the null pointer exception? Which one did Rohan work on yesterday?</p>
<p>Nobody knew. It was chaos wrapped in confusion, delivered via a 16GB SanDisk pendrive.</p>
<h2 id="heading-the-email-attachment-disaster">The Email Attachment Disaster</h2>
<p>When pendrives failed us, we tried emails. Zip the project, send with subject "Latest Code - FINAL VERSION", teammate downloads, makes changes, emails back. My inbox became a graveyard of "Re: Re: Re: Project Code".</p>
<p>Which email had the working code? Tuesday 2:47 PM or Wednesday 11:23 PM? Want to see last week's version? Good luck digging through 47 emails. Sometimes Gmail compressed attachments and killed your indentation. Or files corrupted during download. Or someone worked on last week's version by mistake.</p>
<h2 id="heading-when-things-got-real">When Things Got Real</h2>
<p>The real disaster struck during our final year project. We were a team of four, building a web application. By this time, we'd upgraded from pendrives to Google Drive (we thought we were so modern). Everyone was editing the same files, and Google Drive would helpfully create "conflicted copies" with timestamps.</p>
<p>I remember one particularly painful night. We had a demo the next morning. I opened the project folder on Google Drive and saw this:</p>
<pre><code class="lang-plaintext">app.js
app (Rohan's conflicted copy 2021-03-15).js
app (Priya's conflicted copy 2021-03-15).js
app (1).js
app (2).js
app_final.js
</code></pre>
<p>Seven versions of the same file. Each person had been editing their own copy thinking they were working on the latest version. We spent three hours manually comparing files, copying and pasting code, trying to merge everything together. We literally sat in a circle, each person reading out their changes while one person typed everything into a "final" file.</p>
<p>We missed the demo. Well, we showed up, but the application was so broken that the professor just shook his head and walked away.</p>
<h2 id="heading-the-team-collaboration-nightmare">The Team Collaboration Nightmare</h2>
<p>The absolute worst part? No accountability or history.</p>
<p>Login worked Monday. Broken Wednesday. Who changed it? What changed? Why? Nobody knew. Hours spent debugging, only to find someone "accidentally" deleted three lines.</p>
<p>No way to see who did what. No way to revert to Monday's version without losing everything else. Want to experiment? Copy the entire project, rename it "project_search_experiment", make changes, manually copy code back if it works. Two people trying different approaches? Forget it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769777012112/197c5654-c37a-4bf3-b06e-8ab89d1281d9.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-final-version-that-never-was">The "Final Version" That Never Was</h2>
<p>11:30 PM: "Final working version" ready. Everything tested. Submitted.</p>
<p>11:45 PM: "Hey, I just pushed a small optimization. Just two lines."</p>
<p>It broke everything. We'd already submitted the old version. No way to see what changed without manual comparison. Or worse – we'd submit the broken version thinking it was better.</p>
<h2 id="heading-when-version-control-became-my-savior">When Version Control Became My Savior</h2>
<p>Fast forward to 2021, during the lockdown. That's when my college mate introduced me to Git. And I remember thinking, "Where has this been all my life?"</p>
<p>Suddenly, all these problems I'd been facing all the chaos, the lost changes, the "final_final_v2" madness it all had a solution. A proper, elegant, well-thought-out solution.</p>
<p>With Git:</p>
<ul>
<li><p>Every change was tracked. Not just what changed, but who changed it and why.</p>
</li>
<li><p>I could see the entire history of my project. Want to see what the code looked like last Tuesday? One command.</p>
</li>
<li><p>Working on experimental features? Create a branch. If it works, merge it. If it doesn't, delete it. The main code stays safe.</p>
</li>
<li><p>Collaboration became smooth. Multiple people could work on the same project simultaneously without overwriting each other's work.</p>
</li>
<li><p>No more "final" versions. Every commit was a checkpoint. Every checkpoint was accessible.</p>
</li>
</ul>
<h2 id="heading-the-real-problem-version-control-solved">The Real Problem Version Control Solved</h2>
<p>The pendrive problem wasn't about pendrives. It was about managing changing code over time and across people.</p>
<p>Before version control, we lacked:</p>
<ul>
<li><p>Reliable change tracking</p>
</li>
<li><p>Conflict-free collaboration</p>
</li>
<li><p>Safe experimentation</p>
</li>
<li><p>Time travel for debugging</p>
</li>
<li><p>Clear history of changes</p>
</li>
</ul>
<p>We were solving a multi-dimensional problem (code + time + people + dependencies) with one-dimensional tools (files and folders). Like playing a video game with only a keyboard when it needs a controller.</p>
<h2 id="heading-the-lessons-i-learned">The Lessons I Learned</h2>
<p>If there's one thing my pendrive disaster days taught me, it's this: the right tool for the job makes all the difference.</p>
<p>We spent hours no, days dealing with problems that version control solves in seconds. We lost work, we lost sleep, we lost grades, all because we were using the wrong tools for the job.</p>
<p>The pendrive problem exists because developers are trying to manage complex, evolving codebases using tools designed for static file storage. It's a mismatch between the problem and the solution.</p>
<p>Version control systems exist because someone looked at the chaos we were all dealing with and said, "There has to be a better way." And they were right.</p>
<p>So if you're still saving files as "project_v1", "project_v2", "project_final", or passing around pendrives and email attachments, stop. Just stop. Learn Git. Learn any version control system. Your future self will thank you. Your teammates will thank you. Your grades will thank you.</p>
<p>Trust me, I learned this the hard way. You don't have to.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[I didn't need Git just for Coding, I Needed it for Everything]]></title><description><![CDATA[That's what I told myself when my college mate gave me a quick walkthrough over Git back in 2021 during lockdown. And I was like, why haven't I used this tool from my school days for my assignments, for my projects, for everything? I felt like every ...]]></description><link>https://blog.priyanshumaitra.dev/git-history-basics-and-essential-commands</link><guid isPermaLink="true">https://blog.priyanshumaitra.dev/git-history-basics-and-essential-commands</guid><category><![CDATA[Git]]></category><category><![CDATA[version control systems]]></category><category><![CDATA[version control]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[ChaiCode]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[Developer Tools]]></category><category><![CDATA[Git Commands]]></category><dc:creator><![CDATA[Priyanshu Maitra]]></dc:creator><pubDate>Thu, 15 Jan 2026 18:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769756896277/a64ed288-0620-439f-b460-cddb6c0d998f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>That's what I told myself when my college mate gave me a quick walkthrough over Git back in 2021 during lockdown. And I was like, why haven't I used this tool from my school days for my assignments, for my projects, for everything? I felt like every software where we save our work by pressing <code>CTRL+S</code> should have git built within it. Well, that was my introduction to git.</p>
<p>Prior to that, my <code>playground</code> folder (yeah, that's the name of my project folder, pretty cool right? :) used to look something like this. Multiple FINAL versions of the same file named like this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769534569223/5a7f1ceb-ff87-43be-8d53-1a06e87292ac.png" alt="A computer file explorer window shows seven blue folders labeled: &quot;college final project,&quot; &quot;college final project [FINAL],&quot; &quot;fronend,&quot; &quot;frontend 2,&quot; &quot;portfolio site,&quot; &quot;portfolio site final,&quot; and &quot;portfolio site final 2.&quot; The sidebar has options like Home, Desktop, and Downloads." class="image--center mx-auto" /></p>
<p>If you've been there, you know the pain. Now, let me tell you about Git and how it changed everything for me.</p>
<h2 id="heading-what-is-git">What is Git?</h2>
<p>Git is a version control system(VCS) that tracks changes in your files and helps you manage different versions of your projects.</p>
<p>Git works locally inside of your project directory by default. It keeps track of your changes in your project folder in a versioned manner without any fuzz. Exactly like you keep a snapshot(backup) of your PC/Laptop in case if it runs into a problem then you can restore from any point.</p>
<p>But here's the interesting part about its origin story that I find fascinating.</p>
<p>Git was created by Linus Torvalds in 2005. Yes, the same guy who created Linux. And here's the fascinating part - Git was actually a side project of his that he built while working on his main project, Linux itself. The Linux kernel development team was using a proprietary version control system called BitKeeper, but when they lost access to it due to licensing issues, Linus decided to build his own. And he did it in just a few weeks.</p>
<h2 id="heading-why-git-is-used">Why Git is Used?</h2>
<p>Before Git, I used to create multiple copies of my files manually. Every time I wanted to try something new or make a significant change, I'd duplicate the entire folder. My desktop was a mess of folders named "project_backup", "project_backup_2", "project_old", and the classic "project_final_final_thisone".</p>
<p>Git solves this chaos beautifully. Here's why developers like us use it:</p>
<ul>
<li><p><strong>Version Control Without the Mess</strong>: Git keeps track of every change you make to your code. Want to see what your code looked like three weeks ago? Git has got your back. Made a mistake and want to go back? No problem. You don't need twenty copies of the same file with different names.</p>
</li>
<li><p><strong>Collaboration Made Easy</strong>: When I started working on our final year project in my Diploma, Git became indispensable. Multiple people can work on the same project simultaneously without overwriting each other's work. You can work on your feature while your teammate works on theirs, and Git helps you merge everything together.</p>
</li>
<li><p><strong>Experimentation Without Fear</strong>: Want to try out a crazy new idea but afraid you'll break your working code? With Git, you can create a separate branch, experiment all you want, and if things don't work out, your main code is still safe and sound.</p>
</li>
<li><p><strong>Work from Anywhere</strong>: Since Git is distributed, you have the complete history of your project on your local machine. No need to be connected to a central server to see your project history or make commits.</p>
</li>
</ul>
<h2 id="heading-git-basics-and-core-terminologies">Git Basics and Core Terminologies</h2>
<p>Before diving into commands, let's understand some fundamental concepts that form the backbone of Git. Trust me, understanding these will make everything else click.</p>
<ul>
<li><p><strong>Git Repository (Repo)</strong>: Think of a repository as a special folder that Git watches over. When you initialize a Git repository in your project folder, Git starts tracking all the changes happening inside that folder. It's like putting your project under surveillance, but in a good way. Your repository contains all your files plus a hidden <code>.git</code> folder where Git stores all the version history and metadata.</p>
</li>
<li><p><strong>Tracked Files(Staging Area)</strong>: Not all files in your repository are automatically tracked by Git. A tracked file is one that Git knows about and monitors for changes. When you create a new file, Git sees it as "untracked" until you explicitly tell Git to start tracking it using the <code>git add &lt;file_name&gt;</code> command.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769718974066/2845eec1-58bc-4cf9-b055-765a03ef5f7b.png" alt="Diagram illustrating the Git workflow, showing three stages: Working Directory, Staging Area, and Repository (.git directory). It includes arrows for actions: &quot;checkout the project&quot; from Repository to Working Directory, &quot;stage changes&quot; from Working Directory to Staging Area, and &quot;commit&quot; from Staging Area to Repository." class="image--center mx-auto" /></p>
</li>
<li><p><strong>Commit</strong>: Think of a commit as a snapshot of your project at a specific point in time. You created a file, made some changes in an existing file, and want to finalize those changes to the next version of the project. That's when you perform a commit, to finalize, locally. Each commit has a unique identifier (a hash) and contains a message describing what you changed. It's like taking a photograph of your project that you can always return to.</p>
</li>
<li><p><strong>Branch</strong>: This is one of Git's most powerful features. A branch is essentially a parallel version of your repository. The default branch is usually called "main" or "master". Branch is what enabled me and my teammate to work on our respective parts and features at the same time, and merge them to the main one after it got finished. I could be working on adding a login feature in a "login-feature" branch while my teammate works on fixing bugs in a "bugfix" branch, and the main branch stays stable.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769753541211/634cf668-fac4-4155-9f30-b5e07fd68439.png" alt="Diagram illustrating the internal flow of Git branching. It shows the sequences for Feature 1 and Feature 2 branches, with steps like &quot;feature added,&quot; &quot;feature enhanced,&quot; &quot;bug fix,&quot; and merging processes with the Main Branch." class="image--center mx-auto" /></p>
</li>
<li><p><strong>HEAD</strong>: HEAD is a pointer that tells you where you currently are in your Git repository. Most of the time, HEAD points to the latest commit of the branch you're currently on. When you switch branches, HEAD moves to point to that branch. It's like a "you are here" marker on a map.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769753711335/8e020f75-090e-42af-a0f3-a739a54b0636.png" alt="Diagram explaining the concept of HEAD in Git. Shows three commits on a main branch with arrows indicating direction. The HEAD pointer can move between commits, pointing to the current commit. Examples show HEAD pointing to commit 1, commit 2, and commit 3." class="image--center mx-auto" /></p>
</li>
</ul>
<h2 id="heading-common-git-commands">Common Git Commands</h2>
<p>Now that we understand the concepts, let's look at the commands you'll use every day. I'll walk you through them in the order you'd typically use them when starting a project.</p>
<h3 id="heading-git-init"><code>git init</code></h3>
<p>This is where everything begins. <code>git init</code> initializes a new Git repository in your current directory.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> your-project-folder
git init
</code></pre>
<p>When you run this command, Git creates that hidden <code>.git</code> folder I mentioned earlier. Your project is now a Git repository. This is what I wish I'd done with my "playground" folder from day one.</p>
<h3 id="heading-git-clone"><code>git clone</code></h3>
<p>But what if the project already exists somewhere, like on GitHub? Instead of <code>git init</code>, you use <code>git clone</code> to download an existing repository to your local machine.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/username/repository-name.git
</code></pre>
<p>This downloads the entire project, including all its history, to your computer. I use this every time I want to contribute to an open-source project or when starting work on a team project.</p>
<h3 id="heading-git-status"><code>git status</code></h3>
<p>This is probably the command I use the most. <code>git status</code> shows you the current state of your repository. Which files have been modified? Which files are staged? Which files are untracked?</p>
<pre><code class="lang-bash">git status
</code></pre>
<p>It's like asking Git, "What's happening right now?" The output tells you exactly where things stand, which is incredibly helpful when you're in the middle of making changes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769754379378/7ef99425-b865-4d00-b6b9-aa8c06c8a2da.png" alt="Command line interface showing a Git repository status. It includes files `app.py`, `index.html`, and `style.css` as untracked, with a prompt to use &quot;git add&quot; to track them. The repository is on the master branch with no commits yet." class="image--center mx-auto" /></p>
<h3 id="heading-git-add"><code>git add</code></h3>
<p>Once you've made changes to your files, you need to stage them before committing. <code>git add</code> moves your changes to the staging area.</p>
<pre><code class="lang-bash">git add file-name
</code></pre>
<p>To add all modified files at once:</p>
<pre><code class="lang-bash">git add .
</code></pre>
<p>This is the step where you decide which changes you want to include in your next commit. I used to add everything at first, but now I'm more selective, making smaller, focused commits.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769754462857/82d7a885-235d-4e93-a863-2e86601ddad2.png" alt="CLI image showing a Git workflow. Commands used: `git add .` and `git status`. Three new files, `app.py`, `index.html`, and `style.css`, are staged for commit. Git version 3.13.5 displayed." class="image--center mx-auto" /></p>
<h3 id="heading-git-commit"><code>git commit</code></h3>
<p>After staging your changes, you commit them to your local repository with a message describing what you did.</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"type your commit message here"</span>
git commit -am <span class="hljs-string">"type your commit message here"</span>
</code></pre>
<p>The <code>-m</code> flag lets you add a message right there in the command. Your commit message should be clear and descriptive. Instead of "fixed stuff", write "Fix login button alignment on mobile devices". Your future self (and your teammates) will thank you.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769754530994/a44ced60-76be-486f-9e12-07897ea3292b.png" alt="Terminal screenshot showing a `git commit` command with the message &quot;setup project.&quot; It indicates three new files: `app.py`, `index.html`, and `style.css`, with 11 insertions. The command prompt indicates Python version 3.13.5." /></p>
<h3 id="heading-git-log"><code>git log</code></h3>
<p>Want to see the history of your project? <code>git log</code> shows you all the commits made to your repository.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span>
</code></pre>
<p>This gives you a detailed view, but I prefer:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span> --oneline
</code></pre>
<p>This gives you a compact, one-line summary of each commit. Much easier to scan through when you're looking for something specific.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769754593546/a39a1bca-5cf1-408d-bae7-1ec7d5e9ac0e.png" alt="A terminal screenshot showing a branch named &quot;master&quot; in a git repository. The `git log --oneline` command displays one commit: &quot;81accad (HEAD -&gt; master) setup project&quot;. The interface also indicates Python version 3.13.5." /></p>
<h3 id="heading-git-diff"><code>git diff</code></h3>
<p>Before committing, I often want to see exactly what I changed. <code>git diff</code> shows you the differences between your working directory and the staging area.</p>
<pre><code class="lang-bash">git diff
</code></pre>
<p>To see differences in staged files:</p>
<pre><code class="lang-bash">git diff --staged
</code></pre>
<p>This command has saved me countless times from committing debug code or console.log statements I forgot to remove.</p>
<h3 id="heading-git-branch"><code>git branch</code></h3>
<p>Branches are where Git truly shines for project management. To see all branches:</p>
<pre><code class="lang-bash">git branch
</code></pre>
<p>To create a new branch:</p>
<pre><code class="lang-bash">git branch feature-branch-name
</code></pre>
<p>To switch to that branch:</p>
<pre><code class="lang-bash">git checkout feature-branch-name
</code></pre>
<p>Or do both in one command:</p>
<pre><code class="lang-bash">git checkout -b feature-branch-name
</code></pre>
<p>I create a new branch for every feature I work on. It keeps things organized and makes it easy to work on multiple things without them interfering with each other.</p>
<h3 id="heading-git-push"><code>git push</code></h3>
<p>You've made commits locally, but your teammates can't see them yet. <code>git push</code> uploads your commits to a remote repository like GitHub.</p>
<pre><code class="lang-bash">git push origin main
</code></pre>
<p>This pushes your "main" branch to the remote repository named "origin". The first time you push a new branch, you'll need:</p>
<pre><code class="lang-bash">git push -u origin branch-name
</code></pre>
<p>The <code>-u</code> flag sets up tracking, so future pushes from that branch can just be <code>git push</code>.</p>
<h3 id="heading-git-reset"><code>git reset</code></h3>
<p>Made a mistake and want to undo a commit? <code>git reset</code> is your friend, but be careful with it.</p>
<p>To unstage files without losing changes:</p>
<pre><code class="lang-bash">git reset file-name
</code></pre>
<p>To undo the last commit but keep the changes:</p>
<pre><code class="lang-bash">git reset --soft HEAD~1
</code></pre>
<p>To completely discard the last commit and all its changes:</p>
<pre><code class="lang-bash">git reset --hard HEAD~1
</code></pre>
<p>I try to avoid <code>--hard</code> unless I'm absolutely sure, because it permanently deletes changes.</p>
<h3 id="heading-git-revert"><code>git revert</code></h3>
<p>Unlike <code>git reset</code>, which rewrites history, <code>git revert</code> creates a new commit that undoes the changes from a previous commit. This is safer when working with shared branches.</p>
<pre><code class="lang-bash">git revert commit-hash
</code></pre>
<p>If you realize a commit broke something and others have already pulled your changes, <code>git revert</code> is the way to go.</p>
<h3 id="heading-git-rebase"><code>git rebase</code></h3>
<p>Rebasing is a more advanced technique that helps keep your branch history clean. When you rebase, you're essentially moving your branch to start from a different point.</p>
<pre><code class="lang-bash">git rebase main
</code></pre>
<p>This takes all your commits from the current branch and replays them on top of the main branch. It's great for keeping a linear history, but never rebase commits that you've already pushed to a shared repository, as it rewrites history and can cause problems for your teammates.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Looking back at my pre-Git days, I can't believe I managed without it. Git has become more than just a tool for code – I use it for my blog posts, documentation, configuration files, and even my thesis. That instinct I had back in 2021, that everything should have Git built in? I still feel that way.</p>
<p>The commands I've covered here are just the beginning. Git has a lot more to offer, but mastering these basics will take you far. Start simple, use it daily, and gradually you'll discover more powerful features as you need them.</p>
<p>If you're still saving files as "final_project_1", "final_project_2", it's time to stop. Initialize a Git repository, make your first commit, and never look back. Your future self will thank you for it.</p>
<p>I have always wondered what’s inside of <code>.git</code> folder and how git runs internally. Well more about that in my next blog.</p>
<p>Till then…</p>
<p>If you are looking for a more in-depth git tutorial, you can refer to the <a target="_blank" href="https://git-scm.com/docs">official git docs</a> and our beloved <a target="_blank" href="https://docs.chaicode.com/youtube/chai-aur-git/introduction/">ChaiDocs</a>.</p>
]]></content:encoded></item></channel></rss>