<?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[Tuanhadev Blog]]></title><description><![CDATA[tuanhadev]]></description><link>https://blog.tuanhadev.tech</link><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 10:43:47 GMT</lastBuildDate><atom:link href="https://blog.tuanhadev.tech/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[My experience of using AI Agents]]></title><description><![CDATA[AI Questions
What are the real differences between Vibe Coding and Agentic Engineering?
This is the part most explainers get wrong. They describe agentic engineering as “using better AI tools” or “mor]]></description><link>https://blog.tuanhadev.tech/my-experience-of-using-ai-agents</link><guid isPermaLink="true">https://blog.tuanhadev.tech/my-experience-of-using-ai-agents</guid><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Thu, 19 Mar 2026 11:39:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/bfff5a6a-4c20-49e5-804f-911c35db7110.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>AI Questions</h2>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">What are the real differences between Vibe Coding and Agentic Engineering?</mark></strong></p>
<p>This is the part most explainers get wrong. They describe agentic engineering as “using better AI tools” or “more automation.” That’s not it.</p>
<p>Vibe coding means going with the vibes and not reviewing the code. That’s the defining characteristic. You prompt, you accept, you run it, you see if it works. If it doesn’t, you paste the error back in and try again.</p>
<p><mark class="bg-yellow-200 dark:bg-yellow-500/30">The problem isn’t the AI. The problem is the human not reviewing what the AI built.</mark></p>
<p><mark class="bg-yellow-200 dark:bg-yellow-500/30">Agentic engineering means AI does the implementation, human owns the architecture, quality, and correctness. You might write only a fraction of the code by hand. The rest comes from agents working under your direction. That’s agentic. And you’re applying engineering discipline throughout.</mark></p>
<p>Same tools. Completely different discipline.</p>
<p><strong>The one-line distinction:</strong></p>
<blockquote>
<p><em>Vibe coding = YOLO. Agentic engineering = AI builds, human owns.</em></p>
</blockquote>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">What is Harness Engineering?</mark></strong></p>
<p>To understand where harness engineering fits, here’s how it relates to the other disciplines you’ve probably heard about:</p>
<ul>
<li><p><strong>Prompt Engineering</strong> → Single interaction to craft the best input to the model (single request-response interaction).</p>
</li>
<li><p><strong>Context Engineering</strong> → Control what the model sees during a whole session (multiple interactions until clearing).</p>
</li>
<li><p><strong>Harness Engineering</strong> → Designs the environment, tools, guardrails, and feedback loops (multiple sessions).</p>
</li>
<li><p><strong>Agent Engineering</strong> → Design the agent’s internal reasoning loop (define specialized agents).</p>
</li>
<li><p><strong>Platform Engineering</strong> → Infrastructure to manage deployment, scaling, and cloud operations (where agents can run).</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/43b7cf3c-1e58-43b0-b10b-6d73a5dde110.webp" alt="" style="display:block;margin:0 auto" />

<p>Prompt engineering is about what you say to the model.</p>
<p>Context engineering is about what the model sees.</p>
<p>Harness engineering is about the entire world the model operates in. It includes the tools the agent can call, the constraints it cannot violate, the documentation structure it reads, and the automated feedback loops that catch its mistakes before they reach production</p>
<hr />
<p><strong>What is the llm.txt for?</strong></p>
<p><code>llm.txt</code> is a site-level instruction file for AI/LLM agents, like <code>robots.txt</code> but for models. It tells models what the site is about and which sources to prioritize. Example: a site could point models to its official docs and API reference; the spec and examples are described at <a href="https://llmstxt.org/">https://llmstxt.org/</a> (which you can follow to publish your own).</p>
<hr />
<p><strong>What even is the difference? They all seem like "AI configuration stuff."</strong></p>
<p>Yep, fair. Think of it this way:</p>
<ul>
<li><p><strong>Instructions</strong> = Passive rules are always applied in the background</p>
</li>
<li><p><strong>Agents</strong> = Custom AI personas you manually switch into</p>
</li>
<li><p><strong>Skills</strong> = Step-by-step playbooks you explicitly invoke for a specific task</p>
</li>
</ul>
<p><strong>So instructions just... always run?</strong></p>
<p>Yes — automatically. The <code>applyTo</code> frontmatter pattern controls <em>when</em> they're injected. For example, context-engineering.instructions.md has <code>applyTo: '**'</code> so it's always active. The nextjs.instructions.md has <code>applyTo: '**/*.tsx, **/*.ts, ...'</code> so it only kicks in when you're editing TypeScript/JSX files.</p>
<p>You don't call them. Copilot just silently reads them and adjusts its suggestions accordingly. They're like a standing memo on your desk — always there.</p>
<p><strong>When would I actually switch to a custom agent mode?</strong></p>
<p>When you want a fundamentally different <em>persona and toolset</em> for a session. Look at debug.agent.md — it locks in a specific tool list (terminal, tests, problems panel) and a structured debugging workflow. Or expert-nextjs-developer.agent.md — it declares expertise, forces certain behaviors, and even pins a model (<code>GPT-4.1</code>).</p>
<p>Basically: use an agent when "default Copilot" isn't the right mindset for the job. Debugging, writing a PRD, doing a technical spike — those all benefit from a mode switch.</p>
<p><strong>What about skills — do those auto-load like instructions?</strong></p>
<p>Nope. Skills are NOT automatically loaded. They're on-demand playbooks. You invoke them explicitly by referencing them in a prompt, or by having an agent that knows to use them.</p>
<p>For example, conventional-commit won't do anything unless you tell Copilot "use the conventional-commit skill" or you build it into an agent's workflow. Think of skills as reusable procedures stored in a drawer — they only run when someone pulls them out.</p>
<p><strong>What's the loading order/hierarchy when Copilot runs?</strong></p>
<p>Roughly:</p>
<ol>
<li><p>copilot-instructions.md — loaded first, always, the main entry point</p>
</li>
<li><p><code>.github/instructions/*.</code><a href="http://instructions.md"><code>instructions.md</code></a> — auto-applied based on <code>applyTo</code> matching your open file</p>
</li>
<li><p><code>.github/agents/*.</code><a href="http://agent.md"><code>agent.md</code></a> — only loaded when you explicitly switch to that agent mode in the Copilot chat panel</p>
</li>
<li><p><code>.github/skills/*/</code><a href="http://SKILL.md"><code>SKILL.md</code></a> — only loaded when explicitly invoked</p>
</li>
</ol>
<p><strong>When do I use each?</strong></p>
<ul>
<li><p><strong>Instructions</strong>: Set-and-forget rules (tech constraints, code style, a11y rules, security guidelines)</p>
</li>
<li><p><strong>Custom Agent</strong>: When you need a different "mode" — debugging, planning, writing specs</p>
</li>
<li><p><strong>Skill</strong>: When you have a repeatable multi-step workflow you want to reuse without re-explaining every time</p>
</li>
</ul>
<hr />
<p><strong>What is AGENTS.md, and who is it for?</strong></p>
<p>AGENTS.md is a universal guide following the agents.md open spec. It targets any AI coding agent (Claude, Gemini, OpenAI Codex, etc.) and covers setup commands, project structure, testing patterns, and workflow — anything tool-agnostic.</p>
<p><strong>What is copilot-instructions.md, and who is it for?</strong></p>
<p>It's a GitHub Copilot-specific file loaded automatically by VS Code. It focuses on IDE-level code generation rules: version constraints, <code>❌ NEVER</code> / <code>✅ ALWAYS</code> generation constraints, and pointers to granular context files in the copilot with <code>applyTo</code> glob patterns.</p>
<p><strong>What content belongs in each file?</strong></p>
<table>
<thead>
<tr>
<th>Content</th>
<th>AGENTS.md</th>
<th>copilot-instructions.md</th>
</tr>
</thead>
<tbody><tr>
<td>Setup / install commands</td>
<td>✅</td>
<td>❌ (link to AGENTS.md)</td>
</tr>
<tr>
<td>Project structure</td>
<td>✅</td>
<td>❌ (link to AGENTS.md)</td>
</tr>
<tr>
<td>Testing instructions</td>
<td>✅</td>
<td>❌ (link to AGENTS.md)</td>
</tr>
<tr>
<td>Code generation constraints</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td><code>applyTo</code> instruction files</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td>Version compatibility rules</td>
<td>❌</td>
<td>✅</td>
</tr>
</tbody></table>
<p><strong>Should they duplicate content?</strong></p>
<p>No. copilot-instructions.md should delegate to AGENTS.md for shared content to avoid drift. Your current setup already does this correctly</p>
<p><strong>What is the single most important design principle?</strong></p>
<p>AGENTS.md is the single source of truth for project facts. copilot-instructions.md is a Copilot-specific lens on top of it — not a copy.</p>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Why shouldn't we let AI write the AGENTS.md?</mark></strong></p>
<p>This is the big one. <a href="https://addyosmani.com/blog/agents-md/">Research has shown</a> (Gloaguen et al., ETH Zurich) that LLM-generated AGENTS.md files offer no benefit and can marginally reduce success rates (~3% on average) while increasing inference costs by over 20%. Developer-written context files, by contrast, provide a modest ~4% improvement. Never let an agent write to <code>AGENTS.md</code> directly. The lead must approve every line. Keep it shorter with clear sections:</p>
<p><a href="https://addyosmani.com/blog/agents-md/">https://addyosmani.com/blog/agents-md/</a></p>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Why does AI-generated AGENTS.md increase the cost of AI?</mark></strong></p>
<p>Here’s the core problem with auto-generated context files. What does <code>/init</code> produce? Codebase overviews. Directory structure. Tech stack description. Module explanations. The ETH Zurich paper found that 100% of Sonnet 4.5’s auto-generated context files contained codebase overviews. 99% of GPT-5.2’s did the same.</p>
<p>These are precisely the things an agent can discover on its own by listing directories and reading your existing READMEs - which it does anyway, regardless of whether AGENTS.md exists. So you’ve added a file that the agent reads, then goes and confirms by reading your actual code, and now has to reconcile two sources of truth. More reasoning tokens. More steps. Same outcome, except slower and more expensive.</p>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">What information should we put in the AGENTS.md?</mark></strong></p>
<p>The practical filter is simple: can the agent discover this on its own by reading your code? If yes, delete it. Every line should represent information that isn’t already in the repo.</p>
<p>That means your AGENTS.md should look more like:</p>
<ul>
<li><p>Use <code>uv</code> for package management</p>
</li>
<li><p>Always run tests with <code>–no-cache</code> or you’ll get false positives from the fixture setup</p>
</li>
<li><p>The auth module uses a custom middleware pattern; do not refactor to standard Express middleware</p>
</li>
<li><p>The <code>legacy/</code> directory is deprecated but imported by three production modules - don’t delete anything in it</p>
</li>
</ul>
<p>And almost nothing else.</p>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">What is the right mindset of AGENTS.md?</mark></strong></p>
<ul>
<li><p>Stop running <code>/init</code>. The auto-generated output is redundant with your existing documentation and adds overhead without benefit, unless your repo has genuinely zero documentation - in which case it’s marginally better than nothing.</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">Before adding any line to AGENTS.md, ask: can the agent find this by reading the code? If yes, don’t write it.</mark></p>
</li>
<li><p>When an agent struggles with something repeatedly, treat it as a codebase problem before treating it as a context problem. Restructure the code. Add a linter rule. Improve the test coverage. Reach for <a href="http://AGENTS.md">AGENTS.md</a> only after you’ve exhausted those options.</p>
</li>
<li><p>If you’re running agents at scale in CI/CD or automated review pipelines, the 15-20% cost overhead from context files compounds across thousands of runs. Calculate it before assuming the tradeoff is worth it.</p>
</li>
<li><p>Consider building a maintenance agent whose job is keeping the context file accurate rather than letting it rot.</p>
</li>
<li><p>And hold your intuitions about what the agent needs loosely. <mark class="bg-yellow-200 dark:bg-yellow-500/30">What seems obviously useful to you might be noise to the model</mark>. The empirical evidence suggests the gap between what we think agents need and what actually helps them is substantial - and probably not in the direction we’d expect.</p>
</li>
<li><p>The instinct to onboard your coding agent like a new hire - give it the office tour, explain the org chart, walk it through the architecture - comes from a reasonable place. But coding agents aren’t new hires. They can grep the entire codebase before you finish typing your prompt. What they need isn’t a map. <mark class="bg-yellow-200 dark:bg-yellow-500/30">They need to know where the landmines are</mark>.</p>
</li>
<li><p>One technique worth trying: start your AGENTS.md nearly empty, and add a single instruction: “<mark class="bg-yellow-200 dark:bg-yellow-500/30">If you encounter something surprising or confusing in this project, flag it as a comment</mark>.” Most of the agent’s proposed additions aren’t things you want to keep permanently - they’re indicators of where the codebase is unclear. Fix those. Keep the file minimal.</p>
</li>
</ul>
<hr />
<p><strong>Why do AI Agents fail on large files?</strong></p>
<p>Large Language Models are probabilistic engines. They predict the next token based on patterns in their context window. When the context window is filled with thousands of lines of structured data, the model’s attention gets diluted. It correctly identifies the node you want to modify, but it loses track of sibling keys, nested brackets, and structural integrity. The result is a file that looks right at the point of change but is broken somewhere else.</p>
<p><strong>What are the common issues that lead to AI failures?</strong></p>
<p>The AI breaks in five specific ways:</p>
<ol>
<li><p><strong>Hallucination from missing context</strong>: The agent doesn’t have the information it needs, so it fills the gap with confident fiction. You asked for a login page and it invented an auth library that doesn’t exist.</p>
</li>
<li><p><strong>State loss in long workflows</strong>: At 10K tokens, the agent is sharp. At 150K, it forgets you wanted dark mode and rebuilds the entire UI in blinding white. Three times.</p>
</li>
<li><p><strong>Tool misuse</strong>: Wrong tool, bad parameters, or just ignoring the output entirely. The agent has access to 15 tools and picks the worst one for the job.</p>
</li>
<li><p><strong>Unproductive loops</strong>: Same failed approach, over and over. Burning tokens with zero progress. The agent version of pulling a door that says “push.”</p>
</li>
<li><p><strong>Silent failure at scale</strong>: Here’s the math nobody mentions: if your agent is 95% accurate per decision and makes 20 decisions per task, it fails more often than it succeeds. Small inaccuracies compound. At production scale, 95% isn’t good enough.</p>
</li>
</ol>
<p><strong>Why do our AI agents get worse over time due to the increase in context window?</strong></p>
<p>LLM output quality degrades as context fills. This isn’t a bug. It’s a property of how transformer attention works. Sharp at 10K tokens. Noticeably worse at 150K on the same tasks.</p>
<p>Think of context management like packing for a backpacking trip. You could bring your entire wardrobe. You’d move slowly and nothing would be easy to find. Pack light instead. Know where to resupply.</p>
<p><strong>In context (what you carry):</strong> system prompt, instruction files, skill headers, the current task.</p>
<p><strong>On disk (available when needed):</strong> full file contents, web search results, codebase, git history. The agent loads these on demand through tools.</p>
<p>In practice, you’ll find that system prompts, MCP tool definitions, and memory files can eat 8-9K tokens before you’ve typed a word. That’s context space not available for reasoning. Audit regularly. Trim what you can.</p>
<p><strong>Compaction</strong> happens when the context hits its limit. The platform summarizes your conversation to free space. It works, but details get lost. Early decisions compress. Tool outputs disappear. Don’t let it surprise you — manage context proactively so the agent doesn’t lose important state at the worst moment.</p>
<hr />
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">How many levels of applying AI Agents in coding work?</mark></strong></p>
<p>Steve Yegge recently described eight stages of how developers grow with AI tools. It's a helpful way to see where you are and where you're going.</p>
<p><strong>Most developers are at Level 3-4. Level 6 begins the orchestration stage, needing different skills than Level 5.</strong></p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/06d0f6c6-af0b-4c17-903c-5b8fe36b6758.jpg" alt="" style="display:block;margin:0 auto" />

<p><strong>What is the shift from conductor to orchestrator?</strong></p>
<p>In the conductor setup, you work with one AI agent in real-time, kind of like pair programming. It's all about guiding that single agent, and everything happens one step at a time within a fixed context. Tools like Claude Code CLI and Cursor's in-editor mode fit this style.</p>
<p>Switching to the orchestrator model is like managing a whole team. You've got multiple agents, each doing their thing with their own context, and they're working independently. You plan everything out, assign tasks, and check in now and then. Tools like Agent Teams, Conductor, Codex, and Copilot Coding Agent are perfect for this approach.</p>
<hr />
<p><strong>What are the single-agent limits?</strong></p>
<p><strong>Every developer eventually runs into three main issues with a single agent: context overload, lack of specialization, and zero coordination. Subagents tackle the first two, while Agent Teams handle all three.</strong></p>
<p>Why can't one agent handle everything? There are three main reasons.</p>
<p>First, context overload. A single agent can only process so much info. Large codebases can overwhelm it, causing you to lose important details as the conversation drags on.</p>
<p>Second, lack of specialization. When one agent tries to do it all—data layer, API, UI, tests—it becomes a jack of all trades, master of none. An agent focused solely on the data layer, for instance, will write much better database code than a generalist trying to juggle everything.</p>
<p>Lastly, no coordination. Even if you bring in helpers, they can't communicate, share tasks, or manage dependencies. Adding more agents without coordination just makes things messier.</p>
<hr />
<p><strong>Why do we need multi-agents?</strong></p>
<p><strong>Parallelism, specialization, isolation, and compound learning don't just add up—they multiply. Three focused agents consistently do better than one generalist working three times as long.</strong></p>
<p>Four reasons to use multiple agents:</p>
<p><strong>Parallelism (3x speed)</strong> - Three agents work on frontend, backend, and tests at the same time.</p>
<p><strong>Specialization (focused work)</strong> - Each agent handles only its own files. An agent focused on db.js writes better database code than one managing everything.</p>
<p><strong>Isolation (safe work)</strong> - Git worktrees give each agent its own space. No merge conflicts while they work.</p>
<p><strong>Compound learning</strong> - An AGENTS.md file collects patterns and tips, improving each session.</p>
<hr />
<p><strong>What is the Subagents pattern?</strong></p>
<p><strong>Subagents are the simplest multi-agent pattern and the one you should try first.</strong></p>
<p>Subagents use the Task tool to spawn specialized child agents from a parent orchestrator. The parent decomposes a task into pieces, spawns subagents for each piece, and manages the dependency graph manually.</p>
<p><strong>What subagents solve:</strong> context isolation per agent, specialization, parallel execution for independent tasks, and it's cost-neutral at roughly 220k tokens total.</p>
<p><strong>What is still missing:</strong> the parent must manually manage the dependency graph. There's no peer messaging between agents. There's no shared task list. And if you're sloppy about file scoping, two agents could write to the same file.</p>
<p>Bottom line: subagents give you parallel execution with manual coordination. That is great for simple decomposition. But when coordination becomes the bottleneck, you need Agent Teams.</p>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">The pro tip of working with hierarchical subagents?</mark></strong></p>
<p>Don't just delegate once. Create feature leads that have their own specialists. This allows for deeper task breakdown without overwhelming anyone.</p>
<p>Instead of the orchestrator creating six subagents, it should create two feature leads. Each lead then creates two or three specialists.</p>
<p>The main orchestrator only communicates with two agents, keeping things simple. Feature Lead A, for example, gets the task "Build the search feature" and breaks it down into Data, Logic, and API subagents. The main orchestrator doesn't need to know these details.</p>
<p>This approach is similar to real engineering teams, where tasks are assigned through layers of tech leads, not directly from the VP of Engineering to individual engineers.</p>
<hr />
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">What is the Agent Team pattern?</mark></strong></p>
<p><strong>Agent Teams add the coordination primitives that subagents lack: a shared task list with dependency tracking, peer-to-peer messaging between teammates, and file locking to prevent conflicts.</strong></p>
<p>Agent Teams are Claude Code's experimental feature for true parallel execution. Enable it with:</p>
<pre><code class="language-javascript">export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
</code></pre>
<p>The architecture has three layers:</p>
<ol>
<li><p><strong>Team Lead</strong> at the top - decomposes work, creates the task list, synthesizes results</p>
</li>
<li><p><strong>Shared Task List</strong> in the middle - tasks with statuses (pending, in_progress, completed, blocked), dependency tracking, and file locking</p>
</li>
<li><p><strong>Teammates</strong> at the bottom - each an independent Claude Code instance with its own context window, running in tmux split panes</p>
</li>
</ol>
<p>Teammates self-claim tasks from the shared list. They message each other directly - peer-to-peer, not through the lead. When a teammate finishes and marks a task complete, any blocked tasks that depended on it automatically unblock. Press <code>Ctrl+T</code> at any time to toggle a visual overlay of the task list.</p>
<hr />
<p><strong>How does the Agent Teams work?</strong></p>
<p><strong>Two mechanisms make Agent Teams work: a shared task list with automatic dependency resolution, and peer-to-peer messaging that prevents the lead from becoming a bottleneck.</strong></p>
<p>The <strong>shared task list</strong> gives each task a status: pending, in_progress, completed, or blocked. Blocked tasks have explicit dependencies. When the backend teammate marks the search API as completed, the blocked test-writing task automatically flips to pending and a teammate picks it up. File locking prevents two teammates from editing the same file simultaneously.</p>
<p><strong>Peer messaging</strong> is the other critical piece. The backend agent tells the frontend agent the API contract directly: "GET /search?q= returns [{id,title,url}]." This doesn't go through the lead. When a teammate goes idle, the lead is automatically notified. This peer-to-peer approach prevents the lead from becoming a coordination bottleneck.</p>
<hr />
<p><strong>How can you manage with 5, 10, or 20+ agents across multiple repos and features?</strong></p>
<p><strong>When you need to manage 5, 10, or 20+ agents across multiple repos and features, you need purpose-built orchestration tools. Every tool in 2026 fits one of three tiers - pick the right tier for the job.</strong></p>
<p>The 2026 tool landscape breaks into three tiers:</p>
<p><strong>Tier 1: In-process subagents and teams</strong></p>
<p>Claude Code subagents and Agent Teams. Single terminal session, no extra tooling needed. Start here.</p>
<p><strong>Tier 2: Local orchestrators</strong></p>
<p>Your machine spawns multiple agents in isolated worktrees. You stay in the loop with dashboards, diff review, and merge control. Best for 3-10 agents on known codebases. Tools include Conductor, Vibe Kanban, Gastown, OpenClaw + Antfarm, Claude Squad, Antigravity, and Cursor Background Agents.</p>
<p><strong>Tier 3: Cloud async agents</strong></p>
<p>Assign a task, close your laptop, return to a pull request. Agents run in cloud VMs. No terminal, no local setup. Tools include Claude Code Web, GitHub Copilot Coding Agent, Jules by Google, and Codex Web by OpenAI.</p>
<p>Most developers in 2026 will use all three tiers - Tier 1 for interactive work, Tier 2 for parallel sprints, Tier 3 to drain the backlog overnight.</p>
<hr />
<p><strong>How do we keep shipping the high-quality code when working with multiple agents?</strong></p>
<p><strong>Three quality gates make agent output trustworthy: plan approval catches bad architecture before code exists, hooks enforce automated checks on every lifecycle event, and AGENTS.md compounds learning across sessions.</strong></p>
<p><strong>Plan approval.</strong> Require teammates to write a plan before they start coding. The lead reviews the approach and approves or rejects. It's far cheaper to fix a bad plan than to fix bad code. The flow looks like:</p>
<pre><code class="language-plaintext">teammate &gt;&gt;&gt; writes plan &gt;&gt;&gt; lead review &gt;&gt;&gt; approve/reject &gt;&gt;&gt; implement
</code></pre>
<p><strong>Hooks.</strong> Automated checks on lifecycle events. A <code>TeammateIdle</code> hook verifies all tests pass before allowing an agent to stop working. A <code>TaskCompleted</code> hook runs lint and tests before marking a task as done. If the hook fails, the agent keeps working until it passes:</p>
<pre><code class="language-plaintext">task done &gt;&gt;&gt; hook runs npm test &gt;&gt;&gt; pass? allow  |  fail? keep working
</code></pre>
<p><strong>AGENTS.md for compound learning.</strong> This file captures discovered patterns, gotchas, and style preferences. Every agent reads it at the start of a session, and every session adds to it. Session one learns about a testing pattern, AGENTS.md is updated, session two avoids the same mistake.</p>
<hr />
<p><strong>What is the Ralph Loop?</strong></p>
<p><strong>The Ralph Loop pattern breaks development into small atomic tasks and runs an agent in a stateless-but-iterative loop. Each iteration: pick task, implement, validate, commit if pass, reset context and repeat. This avoids context overflow while maintaining continuity through external memory.</strong></p>
<p>The five-step cycle:</p>
<ol>
<li><p><strong>Pick</strong> - select the next task from <code>tasks.json</code></p>
</li>
<li><p><strong>Implement</strong> - make the change</p>
</li>
<li><p><strong>Validate</strong> - run tests, types, lint</p>
</li>
<li><p><strong>Commit</strong> - if checks pass, commit and update task status</p>
</li>
<li><p><strong>Reset</strong> - clear the agent context and start fresh with the next task</p>
</li>
</ol>
<p>The key insight is stateless-but-iterative. By resetting each iteration, the agent avoids accumulating confusion. Small bounded tasks produce cleaner code with fewer hallucinations than one enormous prompt.</p>
<h2>AI Tips</h2>
<h3>Establish AI guidelines for the project</h3>
<p><strong>=&gt;</strong> Review the guidelines on instructions, agents, and skills from the <a href="https://github.com/github/awesome-copilot">Awesome Copilot GitHub repository</a>, identify the useful ones, and download them to our source code. To simplify the download process, install the <a href="https://marketplace.visualstudio.com/items?itemName=TimHeuer.awesome-copilot">awesome Copilot extension</a> from the VS Code marketplace. After downloading the guidelines, carefully review them to ensure they fit our codebase.</p>
<p>There are some useful GitHub repos that we can refer to for useful AI Agent guidelines: <a href="https://github.com/anthropics/skills/tree/main">https://github.com/anthropics/skills/tree/main</a>, <a href="https://github.com/obra/superpowers">https://github.com/obra/superpowers</a>, <a href="https://github.com/addyosmani/agent-skills">https://github.com/addyosmani/agent-skills</a>, <a href="https://github.com/codejunkie99/agentic-stack">https://github.com/codejunkie99/agentic-stack</a></p>
<p>Below are some AI guidelines from the GitHub Copilot repository that I use the most:</p>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Copilot Instructions</mark></strong></p>
<ul>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/code-review-generic.instructions.md"><strong>code-review-generic.instructions.md</strong></a>: Instructions for creating effective and portable Agent Skills that enhance GitHub Copilot with specialized capabilities, workflows, and bundled resources.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/context-engineering.instructions.md"><strong>context-engineering.instructions.md</strong></a>: Principles for helping GitHub Copilot understand your codebase and provide better suggestions.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/context7.instructions.md"><strong>context7.instructions.md</strong></a>: Use Context7 proactively whenever the task depends on <strong>authoritative, current, version-specific external documentation</strong> that is not present in the workspace context.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/markdown-accessibility.instructions.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">markdown-accessibility.instructions.md</mark></strong></a>: Markdown accessibility guidelines based on GitHub's 5 best practices for inclusive documentation</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/markdown.instructions.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">markdown.instructions.md</mark></strong></a>: Markdown formatting aligned to the CommonMark specification (0.31.2).</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/memory-bank.instructions.md"><strong>memory-bank.instructions.md</strong></a>: Coding standards, domain knowledge, and preferences that AI should follow.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/nextjs-tailwind.instructions.md"><strong>nextjs-tailwind.instructions.md</strong></a>: Instructions for high-quality Next.js applications with Tailwind CSS styling and TypeScript.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/nextjs.instructions.md"><strong>nextjs.instructions.md</strong></a><strong>:</strong> Best practices for building Next.js (App Router) apps with modern caching, tooling, and server/client boundaries (aligned with Next.js 16.1.1).</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/performance-optimization.instructions.md"><strong>performance-optimization.instructions.md</strong></a>: The most comprehensive, practical, and engineer-authored performance optimization instructions for all languages, frameworks, and stacks.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/instructions/security-and-owasp.instructions.md"><strong>security-and-owasp.instructions.md</strong></a>: Comprehensive secure coding instructions for all languages and frameworks, based on OWASP Top 10 and industry best practices.</p>
</li>
</ul>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Custom Agents</mark></strong></p>
<ul>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/4.1-Beast.agent.md"><strong>4.1-Beast.agent.md</strong></a>: It is a custom “agent profile” that tells Copilot how to behave: keep working until the task is fully solved, use lots of research (including web fetches), plan with to-do lists, test rigorously, and follow specific workflow rules. In short, it is a strict, autonomous mode configuration for long, research-heavy tasks.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/Thinking-Beast-Mode.agent.md">Thinking-Beast-Mode.agent.md</a>: A transcendent coding agent with quantum cognitive architecture, adversarial intelligence, and unrestricted creative freedom.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/aem-frontend-specialist.agent.md"><strong>aem-frontend-specialist.agent.md</strong></a><strong>:</strong> IExpert assistant for developing AEM components using HTL, Tailwind CSS, and Figma-to-code workflows with design system integration</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/blueprint-mode.agent.md"><strong>blueprint-mode.agent.md</strong></a><strong>:</strong> Executes structured workflows (Debug, Express, Main, Loop) with strict correctness and maintainability. Enforces an improved tool usage policy, never assumes facts, prioritizes reproducible solutions, self-correction, and edge-case handling.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/critical-thinking.agent.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">critical-thinking.agent.md</mark></strong></a>: Challenge assumptions and encourage critical thinking to ensure the best possible solution and outcomes.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/debug.agent.md"><strong>debug.agent.md</strong></a>: Debug your application to find and fix a bug.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/demonstrate-understanding.agent.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">demonstrate-understanding.agent.md</mark></strong></a>: Validate user understanding of code, design patterns, and implementation details through guided questioning.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/devils-advocate.agent.md"><strong>devils-advocate.agent.md</strong></a>: I play the devil's advocate to challenge and stress-test your ideas by finding flaws, risks, and edge cases</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/expert-nextjs-developer.agent.md"><strong>expert-nextjs-developer.agent.md</strong></a>: Expert Next.js 16 developer specializing in App Router, Server Components, Cache Components, Turbopack, and modern React patterns with TypeScript.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/expert-react-frontend-engineer.agent.md"><strong>expert-react-frontend-engineer.agent.md</strong></a>: Expert React 19.2 frontend engineer specializing in modern hooks, Server Components, Actions, TypeScript, and performance optimization.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/principal-software-engineer.agent.md"><strong>principal-software-engineer.agent.md</strong></a>: Provide principal-level software engineering guidance with focus on engineering excellence, technical leadership, and pragmatic implementation.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/agents/refine-issue.agent.md"><strong>refine-issue.agent.md</strong></a>: Refine the requirement or issue with Acceptance Criteria, Technical Considerations, Edge Cases, and NFRs</p>
</li>
</ul>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Agent Skills</mark></strong></p>
<ul>
<li><p><a href="https://www.patterns.dev/ai/skills/catalog/"><mark class="bg-yellow-200 dark:bg-yellow-500/30">PatternsDev/skills</mark></a><mark class="bg-yellow-200 dark:bg-yellow-500/30">:</mark> <a href="http://Patterns.dev"><strong>Patterns.dev</strong></a> JavaScript Skills: 58 Agent Skills bringing JS, React, and Vue design patterns into your agentic coding workflow!</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/agentic-eval/SKILL.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">agentic-eval</mark></strong></a><mark class="bg-yellow-200 dark:bg-yellow-500/30">:</mark> Patterns and techniques for evaluating and improving AI agent outputs.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/architecture-blueprint-generator/SKILL.md"><strong>architecture-blueprint-generator</strong></a>: Comprehensive project architecture blueprint generator that analyzes codebases to create detailed architectural documentation</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/autoresearch/SKILL.md"><mark class="bg-yellow-200 dark:bg-yellow-500/30">autoresearch</mark></a>: Autonomous iterative experimentation loop for any programming task.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/breakdown-epic-arch/SKILL.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">breakdown-epic-arch</mark></strong></a>: Prompt for creating the high-level technical architecture for an Epic, based on a Product Requirements Document.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/chrome-devtools/SKILL.md"><strong>chrome-devtools</strong></a>: Expert-level browser automation, debugging, and performance analysis using Chrome DevTools MCP. Use for interacting with web pages, capturing screenshots, analyzing network traffic, and profiling performance.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/context-map/SKILL.md"><strong>context-map</strong></a>: Generate a map for all relevant files to a task before making changes</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/conventional-commit/SKILL.md"><strong>conventional-commit</strong></a>: Prompt and workflow for generating conventional commit messages using a structured XML format</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/copilot-instructions-blueprint-generator/SKILL.md">copilot-intructions-blueprint-generator</a>: Technology-agnostic blueprint generator for creating comprehensive copilot-intructions.md files that guide GitHub Copilot to produce code consistent with project standards, architecture patterns, and exact technology versions by analyzing existing codebase patterns and avoiding assumptions.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/create-agentsmd/SKILL.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">create-agentsmd</mark></strong></a>: Prompt for generating an AGENTS.md file for a repository</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/create-implementation-plan/SKILL.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">create-implementation-plan</mark></strong></a>: Create a new implementation plan file for new features, refactoring existing code or upgrading packages, design, architecture or infrastructure.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/create-specification/SKILL.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">create-specification</mark></strong></a>: Create a new specification file for the solution, optimized for Generative AI consumption.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/create-technical-spike/SKILL.md"><strong>create-technical-spike</strong></a>: Create time-boxed technical spike documents for researching and resolving critical development decisions before implementation</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/documentation-writer/SKILL.md"><strong>documentation-writer</strong></a>: Diátaxis Documentation Expert. An expert technical writer specializing in creating high-quality software documentation, guided by the principles and structure of the Diátaxis technical documentation authoring framework</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/doublecheck/SKILL.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">doublecheck</mark></strong></a>: Three-layer verification pipeline for AI output. Extracts verifiable claims, finds supporting or contradicting sources via web search, runs adversarial review for hallucination patterns, and produces a structured verification report with source links for human review</p>
</li>
<li><p><a href="https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md"><mark class="bg-yellow-200 dark:bg-yellow-500/30">skill-creator</mark></a><mark class="bg-yellow-200 dark:bg-yellow-500/30">:</mark> Create new skills, modify, and improve existing skills, and measure skill performance. Use when the user wants to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/model-recommendation/SKILL.md">model-recommendation</a>: Analyze chatmode or prompt files and recommend optimal AI models based on task complexity, required capabilities, and cost-efficiency</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/prd/SKILL.md"><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">prd</mark></strong></a>: Generate high-quality Product Requirements Documents (PRDs) for software systems and AI-powered features. Includes executive summaries, user stories, technical specifications, and risk analysis.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/project-workflow-analysis-blueprint-generator/SKILL.md"><strong>project-workflow-analysis-blueprint-generator</strong></a>: Comprehensive technology-agnostic prompt generator for documenting end-to-end application workflows.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/refactor/SKILL.md"><strong>refactor</strong></a>: Surgical code refactoring to improve maintainability without changing behavior.</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/skills/remember/SKILL.md">remember</a>: Transforms lessons learned into domain-organized memory instructions (global or workspace)</p>
</li>
<li><p><a href="https://github.com/obra/superpowers/blob/main/skills/dispatching-parallel-agents/SKILL.md"><mark class="bg-yellow-200 dark:bg-yellow-500/30">dispatching-parallel-agents</mark></a><mark class="bg-yellow-200 dark:bg-yellow-500/30">:</mark> Use when facing 2+ independent tasks that can be worked on without shared state or sequential dependencies</p>
</li>
<li><p><a href="https://github.com/obra/superpowers/blob/main/skills/executing-plans/SKILL.md"><mark class="bg-yellow-200 dark:bg-yellow-500/30">executing-plans</mark></a><mark class="bg-yellow-200 dark:bg-yellow-500/30">:</mark> Use when you have a written implementation plan to execute in a separate session with review checkpoints</p>
</li>
<li><p><a href="https://github.com/obra/superpowers/blob/main/skills/systematic-debugging/SKILL.md"><mark class="bg-yellow-200 dark:bg-yellow-500/30">systematic-debugging</mark></a><mark class="bg-yellow-200 dark:bg-yellow-500/30">:</mark> Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes</p>
</li>
<li><p><a href="https://github.com/addyosmani/agent-skills/blob/main/skills/using-agent-skills/SKILL.md"><mark class="bg-yellow-200 dark:bg-yellow-500/30">using-agent-skills</mark></a><mark class="bg-yellow-200 dark:bg-yellow-500/30">:</mark> Discovers and invokes agent skills. Use when starting a session or when you need to discover which skill applies to the current task. This is the meta-skill that governs how all other skills are discovered and invoked</p>
</li>
<li><p><a href="https://github.com/addyosmani/agent-skills/blob/main/skills/code-review-and-quality/SKILL.md"><mark class="bg-yellow-200 dark:bg-yellow-500/30">code-review-and-quality</mark></a>: Conducts multi-axis code review. Use before merging any change. Use when reviewing code written by yourself, another agent, or a human. Use when you need to assess code quality across multiple dimensions before it enters the main branch.</p>
</li>
<li><p><a href="https://github.com/addyosmani/agent-skills/blob/main/skills/context-engineering/SKILL.md"><mark class="bg-yellow-200 dark:bg-yellow-500/30">context-engineering</mark></a><mark class="bg-yellow-200 dark:bg-yellow-500/30">:</mark> Optimizes agent context setup. Use when starting a new session, when agent output quality degrades, when switching between tasks, or when you need to configure rules files and context for a project.</p>
</li>
</ul>
<p><strong>MCP</strong></p>
<ul>
<li><p><a href="https://github.com/ChromeDevTools/chrome-devtools-mcp">Chrome DevTools MCP</a>: <code>chrome-devtools-mcp</code> lets your coding agents (such as Gemini, Claude, Cursor, Copilot) control and inspect a live Chrome browser. It acts as a Model Context Protocol (MCP) server, giving your AI coding assistance access to the full power of Chrome DevTools for reliable automation, in-depth debugging, and performance analysis.</p>
</li>
<li><p><a href="https://github.com/upstash/context7">Context7 MCP</a>: Without Context7, LLMs rely on the generic and outdated information about the libraries we use. To resolve that, Context7 pulls up-to-date, version-specific documentations and code examples straight from the source and places them directly into your prompt.</p>
</li>
<li><p><a href="https://github.com/microsoft/playwright-mcp">Playwright MCP</a>: This MCP provides browser automation capabilities using <a href="https://playwright.dev/">Playwright</a>. This server enables LLMs to interact with webpages through structured accessibility snapshots, bypassing the need for screenshots and visually turned models.</p>
</li>
<li><p><a href="https://github.com/atlassian/atlassian-mcp-server">Atlassian MCP Server</a>: The Atlassian Rovo MCP server is a cloud-based bridge between your Atlassian cloud site and compatible tools. Once configured, it enables those tools to interact with Jira, Confluence, and Compass data in real time. This functionality is powered by secure authentication using <strong>OAuth 2.1</strong> or <strong>API tokens</strong>, which ensures all actions respect the user's existing access controls.</p>
</li>
<li><p><a href="https://github.com/mcp/com.figma.mcp/mcp">Figma MCP Server</a>: The Figma MCP Server brings Figma directly into your workflow by providing important design information and context to AI Agents. generating code from Figma design files.</p>
</li>
<li><p><a href="https://ui.shadcn.com/docs/mcp">shadcn/ui MCP</a>: The Shadcn Server allows the AI Assistant to interact with items from registries. We can browse available components, search for specific ones, and install them directly into our project with natural language.</p>
</li>
<li><p><a href="https://github.com/github/github-mcp-server">Github MCP Server</a>: The Github MCP Server connects AI tools directly into Github's platform. This gives AI agents, assistants, and chatbots the ability to read repositories and code files, manage issues and PRs, analyze code, and automate workflows all through natural language interactions.</p>
</li>
<li><p><a href="https://www.youtube.com/redirect?event=video_description&amp;redir_token=QUFFLUhqa1REQmxXRzZTbTJKTFFjSDlqdkVEU29ueFdNZ3xBQ3Jtc0trX0s0RU9INWFVRGNUbDBrYXFlXzFaUk1UUHk4SC1WejdsTGpFa1NBS3hUaVFaZVVwYnpFYnkzd3FFTjZDbklyVHg3emVieWhIUk1YZGRrekJQT3k1VklWT0lqM2lRVi1DcHo2VDRiX2c5QTRnQXdtdw&amp;q=https%3A%2F%2Fpermit.io%2Fmcp-gateway&amp;v=_-28QQsC6cg">Permit's MCP-gateway</a>: Permit MCP Gateway is a drop-in zero-trust proxy that adds authentication, fine-grained authorization, consent, and audit logging to any MCP server. Swap one URL. No code changes. Works with Salesforce, GitHub, Slack, Jira, and any MCP server you already use.</p>
</li>
</ul>
<p><strong>Hooks</strong></p>
<ul>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/hooks/secrets-scanner/README.md">secret-scanner</a>: Scans files modified during a Copilot coding agent session for leaked secrets, credentials, and sensitive data</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/hooks/session-auto-commit/README.md">session-auto-commit</a>: Automatically commits and pushes changes when a Copilot coding agent session ends</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/hooks/session-logger/README.md">session-logger</a>: Logs all Copilot coding agent session activity for audit and analysis</p>
</li>
<li><p><a href="https://github.com/github/awesome-copilot/blob/main/hooks/tool-guardian/README.md">tool-guardian</a>: Blocks dangerous tool operations (destructive file ops, force pushes, DB drops) before the Copilot coding agent executes them</p>
</li>
</ul>
<p><strong>=&gt;</strong> <mark class="bg-yellow-200 dark:bg-yellow-500/30">Let's set up a rule for the AI so that whenever project guideline files are updated or there's a big change in our source code, like updating package versions, the AI automatically checks other documents to ensure everything stays consistent.</mark></p>
<p><strong>=&gt;</strong> <mark class="bg-yellow-200 dark:bg-yellow-500/30">When searching for specific agents, instructions, or skills, simply run the suggest-awesome-copilot-agents, instructions, or skills tools. This will help you find exactly what you need from the awesome Copilot repository.</mark></p>
<h3>Agentic Harness Patterns</h3>
<p><a href="https://generativeprogrammer.com/p/12-agentic-harness-patterns-from">https://generativeprogrammer.com/p/12-agentic-harness-patterns-from</a></p>
<ol>
<li><p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Persistent Instruction File Pattern</mark></strong></p>
<p>Without a persistent instruction file, every agent session starts blank. The user repeats the same conventions, commands, and boundaries each time. The agent makes the same mistakes in session five that it made in session one.</p>
<p>This pattern introduces a durable project-level configuration file loaded automatically at the start of every session. It defines build commands, test commands, architecture rules, naming conventions, and coding standards. It ships with the repo, not with the user’s clipboard.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/30ed168b-605b-461a-93b2-27770a7684af.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when your agent works on a codebase across multiple sessions. The main trade-off is the maintenance burden: the file must stay current as the project evolves, and a stale instruction file can be worse than none if it teaches the agent outdated rules.</p>
</li>
<li><p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Scoped Context Assembly Pattern</mark></strong><br />A single instruction file works for small projects. As a codebase grows, one file either becomes a giant blob that gets ignored, or stays too generic to be useful for any specific directory.</p>
<p>This pattern loads instructions dynamically from multiple files at different scopes: organization, user, project root, parent directories, and child directories. The agent sees different rules depending on where in the codebase it is working. Import syntax allows splitting large instruction sets across files without duplication.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/75f26210-ec9f-4f07-84f1-80cc960b4c65.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this in monorepos, multi-language projects, or any codebase where different directories follow different conventions. The main trade-off is discoverability: when instructions live in many files, it becomes harder to understand what the agent actually sees. Conflicting rules across scopes can produce surprising behavior.</p>
</li>
<li><p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Tiered Memory Pattern</mark></strong></p>
<p>An agent that remembers everything the same way ends up remembering nothing well. Loading all memory into the context window every session wastes tokens, hits size limits, and buries useful information under noise.</p>
<p>This pattern organizes agent memory into distinct layers with different loading strategies. A compact index (capped at 200 lines in Claude Code) stays in context at all times. Topic-specific files load on demand when the current task matches them. Full session transcripts stay on disk and are only searched when needed. One of the most <a href="https://x.com/himanshustwts/status/2038924027411222533">detailed breakdowns</a> of the leaked code confirmed this three-layer design.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/92358bb7-6d0a-453d-a6be-aae0e1e9a5bd.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when your agent runs across multiple sessions and needs to retain preferences, decisions, or workflow state. The main trade-off is the added complexity in deciding what goes where, when to promote or demote information between layers, and how to keep the index in sync with the underlying files.</p>
</li>
<li><p><strong>Dream Consolidation Pattern</strong></p>
<p>Even with tiered memory, agent memory degrades over time. Duplicate entries accumulate, outdated facts contradict new ones, and the index grows until it is no longer compact.</p>
<p>This pattern runs a background process that periodically reviews, deduplicates, prunes, and reorganizes agent memory during idle time. Think of it as garbage collection for agent state. The leaked code revealed an <a href="https://x.com/troyhua/status/2039052328070734102">“autoDream” mode</a> that merges duplicates, prunes contradictions, and keeps the index tight. A separate <a href="https://x.com/ellen_in_sf/status/2039098050837463504">analysis</a> found 8 phases of memory management and 5 types of context compaction.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/16d5c6a2-6c49-4222-8c69-7886ab1b5be5.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when your agent accumulates memory across many sessions and you cannot rely on users to curate it manually. The main trade-off is that the consolidation process itself uses tokens and can make mistakes. An overly aggressive prune might delete something the user still needs.</p>
</li>
<li><p><strong>Progressive Context Compaction Pattern</strong></p>
<p>Long agent sessions eventually hit the context window limit. The agent either loses its earliest context entirely or stops working. Neither is acceptable for tasks that require sustained reasoning across many turns.</p>
<p>This pattern applies multiple stages of compression tuned for different ages of the conversation. Recent turns stay at full detail. Older turns get lightly summarized. Very old turns get aggressively collapsed. The leaked code used four layers: HISTORY_SNIP, Microcompact, CONTEXT_COLLAPSE, and Autocompact, each progressively more aggressive.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/ffa5991e-1ad0-40ef-8502-40b2b2d56357.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when sessions regularly exceed 20-30 turns. The main trade-off is lossy compression: every summarization step discards detail, and if the agent later needs something from a collapsed segment, it may hallucinate rather than admit it forgot.</p>
</li>
<li><p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Explore-Plan-Act Loop Pattern</mark></strong><br />When an agent jumps straight to editing files, it makes changes based on incomplete understanding. The result is edits to the wrong files, missed dependencies, and approaches that ignore existing patterns.</p>
<p>This pattern separates the workflow into three phases with increasing write permissions. In the explore phase, the agent can only read, search, and map the codebase. In the plan phase, it discusses the approach with the user. Only in the act phase does it get full tool access. The leaked code showed <a href="https://x.com/DharmiKumbhani/status/2038917827462308308">distinct plan and act phases</a> with system prompts that steer the agent away from editing before it understands the codebase.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/c508b607-b786-458a-9f06-6802fbf40901.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this for any task that touches an unfamiliar codebase or involves non-trivial changes across multiple files. The main trade-off is speed: enforcing exploration and planning adds turns before the agent produces output, which feels slow for simple tasks.</p>
</li>
<li><p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Context-Isolated Subagents Pattern</mark></strong></p>
<p>In a long agentic session, the context window accumulates everything: research findings, planning discussions, code edits, test output, error logs. By the time the agent is deep into editing, its context is polluted with irrelevant material from earlier phases.</p>
<p>This pattern runs separate agents with their own context windows, system prompts, and restricted tool access. Research agents cannot edit code. Planning agents cannot execute commands. Each subagent sees only what it needs for its specific task.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/45c7f0e4-3df8-4d82-8f4f-4fd59f27c97b.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when sessions are long, multi-phase, or involve tasks with very different context needs. The main trade-off is coordination overhead: the main agent must decide what to pass to each subagent, and important nuance from an earlier phase can get lost in the handoff.</p>
</li>
<li><p><strong>Fork-Join Parallelism Pattern</strong></p>
<p>Large tasks that could be split into independent units still run sequentially if the agent can only work on one thing at a time. A migration across 20 files takes 20 sequential steps even though most of those files have no dependencies on each other.</p>
<p>This pattern spawns multiple subagents in parallel, each working in an isolated git worktree on an independent copy of the repo. The parent’s cached context is reused by each fork, making parallel branching essentially free in token cost. Results merge when all branches complete.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/9f907e3b-b300-45cc-85f6-75b7db29327b.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when a task decomposes into independent units that do not depend on each other’s output. The main trade-off is merge complexity: when parallel branches touch overlapping files, the merge can produce conflicts harder to resolve than sequential work would have been.</p>
</li>
<li><p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Progressive Tools Expansion Pattern</mark></strong></p>
<p>Giving an agent access to every available tool at once creates a selection problem. With 60 tools visible, the model spends more time deciding which to use and is more likely to pick the wrong one.</p>
<p>This pattern starts with a small default set (fewer than 20 tools in Claude Code) and activates additional tools on demand. <a href="https://x.com/jpschroeder/status/2038960058499768427">Justin Schroeder noted</a> the deliberately small default set. The agent starts with Read, Edit, Write, Bash, Grep, Glob, and a handful of others. MCP tools, remote tools, and custom skills activate only when needed.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/2ac1edda-9fb2-4d29-b7d0-6a3ecb27139b.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when your agent has access to many tools but most tasks only need a few. The main trade-off is that the expansion logic adds complexity: the harness must decide when to activate tools, and activating too late means the agent wastes turns without the right capability.</p>
</li>
<li><p>**Command Risk Classification Pattern<br />**<br />Letting an agent run arbitrary shell commands without inspection is dangerous. But asking the user to approve every command creates fatigue, and users end up clicking “yes” to everything.</p>
<p>This pattern applies deterministic pre-parsing and per-tool permission gating before execution. Each tool has individual allow, ask, and deny rules with pattern matching. Shell commands pass through a classification layer that parses the verb, flags, and target to assess risk. The <a href="https://x.com/S0nne123/status/2038979121267495277">auto-mode classifier</a> found in the code auto-approves low-risk actions while keeping a safety classifier for anything dangerous.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/43edec1b-89d6-4b80-a969-a33a839d980c.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when your agent can execute shell commands or interact with external systems. The main trade-off is rigidity: a deterministic classifier cannot anticipate every safe or dangerous command, so the rules need ongoing tuning.</p>
</li>
<li><p>**Single-Purpose Tool Design Pattern<br />**<br />When an agent routes every file operation through a general shell (cat, sed, grep, find), the commands are harder to review, harder to permission, and harder for the model to use correctly. A sed command that edits a file looks identical in structure to one that corrupts it.</p>
<p>This pattern replaces the general shell with purpose-built tools for each common operation: FileReadTool, FileEditTool, GrepTool, GlobTool. Each tool has typed inputs, a constrained scope, and its own permission rules. Raschka calls this out explicitly: the harness provides “predefined tools with validated inputs and clear boundaries” rather than allowing improvised commands.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/ee17ef5b-043a-4c85-bc9b-316e39a1a215.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when your agent performs common file and search operations frequently. The main trade-off is flexibility: purpose-built tools cannot cover every edge case, so you still need a general shell as a fallback.</p>
</li>
<li><p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Deterministic Lifecycle Hooks Pattern</mark></strong></p>
<p>Some actions must happen every time without exception: run the formatter after every edit, validate commands before execution, reload configuration when the working directory changes. Relying on the model to remember these through prompt instructions is unreliable. The model will forget, skip, or reinterpret the instruction depending on context pressure.</p>
<p>This pattern runs shell commands or other actions automatically at specific points in the agent lifecycle, outside the prompt entirely. The leaked code includes 25+ hook points such as PreToolUse, PostToolUse, SessionStart, and CwdChanged. Anything that must happen every time belongs in a hook, not in an instruction.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/7aed9d46-f1b3-4aba-a4b1-b87668acf436.webp" alt="" style="display:block;margin:0 auto" />

<p>Use this when you have invariant behaviors that should never be skipped. The main trade-off is debugging difficulty: when something goes wrong in a hook, it can be harder to diagnose than a prompt-level instruction because hooks run outside the conversation.</p>
</li>
</ol>
<h2>Experience of Working with AI</h2>
<h3>Spec-driven development</h3>
<blockquote>
<p>Plan your work before you write code. But rather than writing plans for humans, we're writing plans and tasks for agents.</p>
</blockquote>
<p>What is spec-driven development?</p>
<blockquote>
<p>Instead of prompting first and figuring it out as you go, you start with a spec. It's a short document that defines what you're building, the constraints, and the key decisions—a contract for how your code should behave. The spec becomes the source of truth the agent uses to generate code. Less guesswork. Fewer surprises.</p>
</blockquote>
<p>I see people conflating PRDs, design docs, and specs all the time. They serve completely different purposes, and mixing them up — especially when working with AI agents — causes a lot of confusion down the line.</p>
<p>Here's how I separate them:</p>
<p><strong>Product Requirements Document (PRD)</strong> — For humans. Product managers, stakeholders. Covers what we're building and why — user stories, success metrics, business value. This is your debate document.</p>
<p><strong>Technical Design Document</strong> — For engineers. Covers how we're building it — architecture decisions, scalability trade-offs, security implications. Also reviewed and debated with the team.</p>
<p><strong>AI Spec</strong> — For agents. This is a pure execution document. No debates, no open questions. It translates the finalized decisions from the PRD and design doc into something an agent can act on directly.</p>
<p>Traditional software development has always followed this pattern:</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/daadbb79-369b-4c84-8795-da5c99791fc8.png" alt="" style="display:block;margin:0 auto" />

<p>The process is the same. The audience is different.</p>
<hr />
<p><strong>My Workflow:</strong></p>
<ol>
<li><p><strong>Generate the PRD</strong><br />I use s<code>pec-driven-instructions-workflow.md</code> combined with skills like <code>prd/skill.md</code>, <code>prd.agent.md</code>, or <code>breakdown-epic-pm</code> to generate the initial PRD. For large epics, I first use <code>breakdown-feature-prd</code> to break them down into feature-level PRDs before any implementation starts.</p>
<p><mark class="bg-yellow-200 dark:bg-yellow-500/30">Important: always use your most capable (most expensive) model for these root documents. And never trust the first generated version</mark>. My verification pipeline:</p>
<p>Run <code>doublecheck</code> skill — surfaces inconsistencies and gaps =&gt; Run <code>agentic-eval</code> — makes updates based on the <code>doublecheck</code> report =&gt; Manual review using <code>critical-thinking</code> — go through every single point and make sure you genuinely understand it =&gt; Use agents like <code>principle-software-engineer</code>, <code>devils-advocate</code>, <code>demonstrate-understanding</code>, and <code>refine-issue</code> to stress-test assumptions further.</p>
</li>
<li><p><strong>Generate the Technical Architecture</strong><br />With a solid <code>prd.md</code>, use the <code>breakdown-epic-arch</code> skill to produce the high-level technical architecture for the epic. This becomes your <code>design.md</code>.</p>
</li>
<li><p><strong>Generate the Spec</strong><br />With both <code>prd.md</code> and <code>design.md</code> ready, generate a detailed spec using the <code>create-specification</code> skill combined with the <code>spec-driven-workflow</code> instructions. This <code>spec.md</code> is what agents will actually work from.</p>
</li>
<li><p><strong>Generate the Implementation Plan</strong><br />From <code>spec.md</code>, use <code>create-implementation-plan/SKILL.md</code> to produce a task-by-task <code>plan.md</code>.</p>
</li>
</ol>
<p>At this point you have all four core documents:</p>
<table>
<thead>
<tr>
<th>File</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>prd.md</code></td>
<td>What &amp; why</td>
</tr>
<tr>
<td><code>design.md</code></td>
<td>How (architecture)</td>
</tr>
<tr>
<td><code>spec.md</code></td>
<td>Execution details for agents</td>
</tr>
<tr>
<td><code>plan.md</code></td>
<td>Task-by-task implementation steps</td>
</tr>
</tbody></table>
<p><mark class="bg-yellow-200 dark:bg-yellow-500/30">Review all four before touching any code.</mark></p>
<hr />
<p><strong>During Implementation</strong></p>
<p>Even with a solid plan, I don't just hand tasks over and walk away. My rules:</p>
<ul>
<li><p><strong>Run</strong> <code>doublecheck</code> <strong>before every task</strong> — pull in external resources to verify the approach and understand the full impact of each change before it's made.</p>
</li>
<li><p><strong>Understand everything the AI produces</strong> — not "looks fine." Actually understand each decision and each line. If something's unclear, ask the agent to explain it with <code>demonstrate-understanding</code>.</p>
</li>
<li><p><strong>One task = one commit</strong> — every task on the plan gets its own commit. Keeps history clean and makes it easy to trace what changed and why.</p>
</li>
<li><p><strong>One big task = a new chat session</strong> -- every big task on the plan should be implemented in the new chat session. It keeps the context window fresh; the context window won't be poisoned by the irrelevant information from those previous responses.</p>
</li>
<li><p><strong>Mark tasks as Done</strong> — always tell the agent to update the <code>Complete</code> column in <code>plan.md</code> after finishing each task. Small habit, makes tracking much easier.</p>
</li>
<li><p>For tasks that are too big or too complex, it's better to split them into multiple tasks. If a big task can't be split, we should ask the AI to apply rules or instructions like those in (copilot-thought-logging.instructions.md) for noting AI thoughts to a dedicated memory file to avoid losing context.</p>
</li>
</ul>
<p>=&gt; <mark class="bg-yellow-200 dark:bg-yellow-500/30">We can build a skill named </mark> <code>executing-plans</code> <mark class="bg-yellow-200 dark:bg-yellow-500/30">=&gt; this skill will contain 2 modes (mode 1 : phase review mode, mode 2: task implementation mode) =&gt; mode 1 process (load phase =&gt; using agentic-eval skill to review =&gt; use double-check skill to review =&gt; update relevant docs for consistency =&gt; Report) =&gt; mode 2 process (load task =&gt; implement =&gt; verify: using verification-before-completion skill =&gt; review: using code-review skill =&gt; Mark complete on plan.md)</mark></p>
<p>=&gt; For example, skills like verification-before-completion, code-review, we can look at an example on this powerful <a href="https://github.com/obra/superpowers">Github repo</a> (remember to customize those skills to be suitable with our project, tools, and AI Agent)</p>
<p>=&gt; So every time we need to review each phase before implementation or implement each task in the phase =&gt; we just need to attach <code>executing-plans</code> skill to AI Agent</p>
<hr />
<p><strong>After we completed all tasks in the plan</strong></p>
<p>When we are in this step, there are several things I constantly follow up:</p>
<ul>
<li><p>Requesting AI to review and ensure the current AI documents, such as AGENTS.md, copilot-instructions.md, and other guidelines, are consistent with the updates made in plan.md.</p>
</li>
<li><p>We completed all tasks in plan.md, which doesn't mean we have completely finished the feature. We need to carefully verify the AI's work for any issues we find and ask AI to fix them. Remember to ask AI to note these in the spec folder, <mark class="bg-yellow-200 dark:bg-yellow-500/30">keeping those documents up to date with our code changes</mark>.</p>
</li>
<li><p>To fix any issues we find, let's develop a debugging skill (contain verification health check skill, code-review skill, commit-convention skill, ...) for verifying and resolving them. We can use the debugging skill template available at <a href="https://github.com/obra/superpowers.By">https://github.com/obra/superpowers.By</a> doing this, we simply attach a debugging skill, include the spec folder with all the necessary context for the AI Agent, and provide an issue description. This allows the AI to quickly assist in resolving issues.</p>
</li>
</ul>
<hr />
<p><strong>Keeping Docs in Sync</strong></p>
<p>Docs live in multiple places — the <code>specs/</code> folder in the repo, Jira tickets, Confluence pages — and they drift apart fast.</p>
<p>My rule: whenever a doc changes in one place, all related docs must be updated too. I explicitly tell the AI agent: <em>if you modify a file in the</em> <code>specs/</code> <em>folder, identify and update all related documents across Jira, Confluence, and any other linked sources.</em> It's not a perfect system, but it cuts down on the drift problem significantly.</p>
<p>=&gt; <mark class="bg-yellow-200 dark:bg-yellow-500/30">More upfront work than just prompting and hoping for the best — but once all four documents are locked in and the verification habit is in place, implementation gets surprisingly smooth. And more importantly, you actually understand what was built when it's done.</mark></p>
<hr />
<p><strong>Spec-Driven Workflow with Linear</strong></p>
<blockquote>
<p>Use Linear MCP to give Claude Code direct access to your project management. The agent reads tickets, updates status, creates sub-issues, and follows your workflow — without you copy-pasting descriptions.</p>
</blockquote>
<p>For larger features, combine specs with Linear tickets:</p>
<ol>
<li><p><strong>Write the spec</strong><br />Read my spec template and generate a spec for: user authentication with JWT tokens. Save it to specs/auth.md</p>
</li>
<li><p><strong>Create tickets from the spec</strong><br />Read specs/auth.md and create a parent Linear issue titled "JWT Authentication" in the Auth project, team Engineering.</p>
<p>Then create one sub-issue per task from the spec, linked to the parent. Each sub-issue should reference the spec: "Spec: specs/auth.md"</p>
</li>
<li><p><strong>Works on tickets</strong><br /><code>/implement PROJ-43</code> The agent reads the ticket, finds the spec reference, reads the spec, and implements with full context.</p>
</li>
<li><p><strong>Track Progress</strong><br />Your Linear board now shows:</p>
<ul>
<li><p>Parent issue with progress bar (auto-calculated from sub-issues)</p>
</li>
<li><p>Each sub-issue moving through: Todo → In Progress → In Review → Done</p>
</li>
<li><p>Comments with PR links on each ticket</p>
</li>
</ul>
<p>You get visibility without doing any project management manually.</p>
</li>
</ol>
<hr />
<h3>Review AI Code</h3>
<p><a href="https://newsletter.owainlewis.com/p/how-i-use-ai-to-review-ai-code">https://newsletter.owainlewis.com/p/how-i-use-ai-to-review-ai-code</a></p>
<p>Here’s the four-layer setup I use. Each layer filters out a category of problems so the next layer sees less noise.</p>
<ol>
<li><p><strong>Automated checks</strong> run your linter, tests, and security scanner before the agent can finish.</p>
</li>
<li><p><strong>Local AI review</strong> gets a second agent to review the code before you push.</p>
</li>
<li><p><strong>CI review</strong> runs AI code review automatically on every PR. The safety net for when you skip step two (it happens)</p>
</li>
<li><p><strong>Human review</strong> handles what’s left: architecture, business logic, and “should we even build this?”</p>
</li>
</ol>
<p>By the time a human looks at the code, the only things remaining are the things only a human can judge.</p>
<p><strong>Layer 1: Automate The Obvious</strong></p>
<p>Claude Code has a feature called hooks. A hook is a shell script that runs automatically at certain points in the agent lifecycle (like when the agent finishes a task). If the script fails, the agent is blocked from completing and has to fix the issues first.</p>
<p>I use a Stop hook that runs my linter and scanner every time Claude finishes work.</p>
<p>The config goes in your Claude Code settings:</p>
<pre><code class="language-plaintext">{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/stop-checks.sh"
          }
        ]
      }
    ]
  }
}
</code></pre>
<p>The script itself is just whatever checks you already run:</p>
<pre><code class="language-plaintext">#!/bin/bash
set -e
rubocop .
brakeman -q
bundle exec rspec --fail-fast
</code></pre>
<p>Swap those for whatever your project uses. Ruff and pytest for Python. ESLint for JavaScript. The point is the same: the agent can’t say “done” until these pass.</p>
<p>This alone catches a surprising amount. Formatting issues, unused imports, type errors, broken tests. None of that makes it into a review.</p>
<hr />
<p><strong>Layer 2: Agent Review</strong></p>
<p>After automated checks pass, review the code yourself and get an AI second opinion before you push.</p>
<p>Two things matter here. First, actually run the code. This sounds obvious but it catches the most embarrassing bugs in two minutes. Second, read the diff. You don’t need to understand every line; understand the shape of the change. What files were touched? Does the scope match what you asked for? Did the agent silently change something you didn’t ask it to?</p>
<p>For the AI review, the key is a fresh context window. Don’t ask the same agent that wrote the code to review it. It has sunk-cost bias and is less likely to challenge its own decisions.</p>
<p>There are a few ways to do this:</p>
<ul>
<li><p><strong>Custom Claude Code command.</strong> A review prompt in .claude/commands/review.md, paired with a REVIEW file at the project root that encodes your project-specific rules. Portable across tools, fully customisable. Claude Code also ships with some built in plugins.</p>
</li>
<li><p><strong>Codex</strong> /review**.** Four presets covering every scenario (base branch, uncommitted changes, specific commit, custom instructions). Priority-ranked findings. The best local review UX I’ve seen. Bonus: writing with Claude and reviewing with Codex means cross-model review built into your workflow. Different models have different blind spots.</p>
</li>
<li><p><strong>CodeRabbit.</strong> /coderabbit:review locally. 40+ linters and scanners running behind the scenes, purpose-built for code review. There are many other great code review tools like Greptile to explore also.</p>
</li>
</ul>
<p>I use a custom review command that reads a REVIEW file at the project root. This file has project-specific rules, things I always want checked.</p>
<pre><code class="language-javascript"># REVIEW.md

## Project Patterns
- Repository pattern for data access. Direct DB queries in handlers are a flag.
- New API routes need an integration test. Flag if missing.
</code></pre>
<p>The general review catches general problems. The project-specific rules catch the things that are unique to your codebase.</p>
<hr />
<p><strong>Layer 3: External Review</strong></p>
<p>Sometimes I forget to run the local review. Sometimes I’m in a rush. So I have an automated check on GitHub that reviews every PR before a human sees it.</p>
<p>There are a few options for this. Codex has a GitHub integration that reviews PRs automatically. CodeRabbit has a GitHub App that does the same thing. Anthropic has an open source GitHub Action for security-focused review.</p>
<p>I like having this as a separate layer because it catches things even when I skip the local step. Set it up once, runs on every PR for free.</p>
<hr />
<p><strong>Layer 4: Human Review</strong></p>
<p>By the time a teammate opens the PR, the linter has passed, tests are green, and an AI has already flagged obvious issues. The human reviewer doesn’t need to catch formatting problems or unused variables.</p>
<p>What’s left is the stuff only a human can judge. Is this the right approach? Does it solve the actual business problem? Will this cause issues in three months? Five minutes of focused review on those questions is more valuable than thirty minutes of line-by-line reading.</p>
<hr />
<p><strong>TL;DR</strong></p>
<p>I spent a long time trying to find the perfect code review setup. The experience was frustrating. There are hundreds of tools, plugins, and approaches, many of them doing the same thing in slightly different ways.</p>
<p>Don’t get lost looking for the perfect solution or perfect prompt. Start with Layer 1. Set up your linter and your hooks; that alone eliminates an entire category of review noise. Then find one way to get an AI review locally that you trust. Add CI when you’re ready.</p>
<p>Start simple and never accept the first output from an agent.</p>
<h2>References</h2>
<p><a href="https://github.com/owainlewis/youtube-tutorials/tree/main">https://github.com/owainlewis/youtube-tutorials/tree/main</a></p>
<p><a href="https://github.com/obra/superpowers">https://github.com/obra/superpowers</a></p>
<p><a href="https://ainative.to/p/ai-agents-full-course-2026">https://ainative.to/p/ai-agents-full-course-2026</a></p>
<p><a href="https://addyosmani.com/blog/code-agent-orchestra/">https://addyosmani.com/blog/code-agent-orchestra/</a></p>
<p><a href="https://awesome-copilot.github.com/learning-hub/">https://awesome-copilot.github.com/learning-hub/</a></p>
<p><a href="https://ai.plainenglish.io/vibe-coding-is-dead-heres-what-replaced-it-aa7d2889b05a">https://ai.plainenglish.io/vibe-coding-is-dead-heres-what-replaced-it-aa7d2889b05a</a></p>
]]></content:encoded></item><item><title><![CDATA[AI Handbook]]></title><description><![CDATA[AI Mindset
Tech hiring in the AI era: Why everyone’s at zero
How AI amplifies developers instead of replacing them, and why this is the React moment all over again.
Headlines scream about tech layoffs]]></description><link>https://blog.tuanhadev.tech/ai-handbook</link><guid isPermaLink="true">https://blog.tuanhadev.tech/ai-handbook</guid><category><![CDATA[AI]]></category><category><![CDATA[ai agents]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Mon, 23 Feb 2026 12:13:19 GMT</pubDate><enclosure url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/00d0a8e4-833f-4a18-84fc-ea3f5c399b4e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>AI Mindset</h1>
<h2>Tech hiring in the AI era: Why everyone’s at zero</h2>
<p><em>How AI amplifies developers instead of replacing them, and why this is the React moment all over again.</em></p>
<p>Headlines scream about tech layoffs at Netflix, Amazon, and Microsoft, but what’s happening beneath the surface tells a different story. In this episode, Taylor Desseyn, VP of Global Community at Torc, joins the We Love Open Source podcast to share why tech hiring isn’t actually dead, how AI changes team composition without replacing developers, and why everyone’s on the same playing field when it comes to learning these new tools.</p>
<p><a class="embed-card" href="https://www.youtube.com/watch?v=KvflH9NMaiU">https://www.youtube.com/watch?v=KvflH9NMaiU</a></p>

<p>Taylor reframes the tech hiring narrative by looking beyond big tech. While FAANG companies (or MANGO, as he’s heard it called now) make layoff headlines, the startup ecosystem is thriving. AI-specific tech startup funding is through the roof. Torc and Randstad are both growing, driven largely by the AI boom. The reality beneath the headlines shows tech hiring evolving, not dying.</p>
<p>AI won’t replace developers, but it will change headcount dynamics. Taylor frames it simply: Think of an engineer as 1.0. With AI tools like Claude or Cursor, that engineer becomes 1.25, 1.5, or even 1.75. A team that previously needed 50 engineers might now need 25 or 20 really good engineers who know how to use AI effectively. It’s not about replacement, it’s about amplification.</p>
<p>For developers worried about AI taking their jobs, Taylor draws a parallel to earlier shifts. He’s been recruiting since 2011, through .NET MVC replacing <a href="http://VB.NET">VB.NET</a> and React’s emergence. AI is the same kind of inflection point. The key insight: <em>Everyone’s at zero right now</em>. Senior, staff, and principal engineers are just getting started with Claude alongside junior developers. It’s a level playing field, but only if you engage.</p>
<h3>Key takeaways</h3>
<ul>
<li><p>Tech hiring is evolving, not dying: Startup ecosystem and AI-specific funding are thriving while big tech layoffs make headlines. Look beneath the surface to see where growth is actually happening.</p>
</li>
<li><p>AI amplifies engineers rather than replacing them: Teams will hire fewer developers but those developers become 1.5x or 1.75x more productive with AI tools. The focus shifts to hiring engineers who know how to use Claude and Cursor effectively.</p>
</li>
<li><p>Everyone’s at zero with AI right now: Senior and junior developers alike are just getting started. Find a mentor, document your learning publicly, and be known for how you’re using AI.</p>
</li>
</ul>
<p>Taylor’s message is clear: This is the React moment for AI. You can ignore it or you can learn it, but everyone who’s learning is starting from the same place. The opportunity is there for developers who take it seriously.</p>
<p><a href="https://allthingsopen.org/articles/tech-hiring-ai-era-everyone-at-zero?ref=dailydev">https://allthingsopen.org/articles/tech-hiring-ai-era-everyone-at-zero?ref=dailydev</a></p>
<p><a href="https://medium.com/@tsecretdeveloper/be-thankful-that-you-were-there-at-the-beginning-of-ai-b47142053d0b">https://medium.com/@tsecretdeveloper/be-thankful-that-you-were-there-at-the-beginning-of-ai-b47142053d0b</a></p>
<p><a href="https://leadershipinchange.com/p/stop-learning-ai-tools">https://leadershipinchange.com/p/stop-learning-ai-tools</a></p>
<p><a href="https://substack.com/home/post/p-188178090?source=queue">https://substack.com/home/post/p-188178090?source=queue</a></p>
<h1>Most Important AI Concepts</h1>
<h2>LLMs</h2>
<p><a href="https://medium.com/mr-plan-publication/not-everything-is-an-llm-8-ai-model-types-you-need-to-know-in-2025-6fb026bcdc82">https://medium.com/mr-plan-publication/not-everything-is-an-llm-8-ai-model-types-you-need-to-know-in-2025-6fb026bcdc82</a></p>
<p><a href="https://substack.com/home/post/p-188649002?source=queue">https://substack.com/home/post/p-188649002</a></p>
<h3><strong>What is Generative AI?</strong></h3>
<p>While today’s generative models are built upon a decade of progress, 2022 was the year when they triggered an “Aha!” moment for most. Generative AI is a subfield of machine learning. It involves training artificial intelligence models on large volumes of real-world data to generate new content (text, images, code, etc.) that resembles human creation.</p>
<p>This may have been a mouthful. Let’s clarify these terms first before we jump into LLMs. Here’s a plain-English map of those first words you’ll see.</p>
<ul>
<li><p><strong>AI</strong> is the big umbrella: getting computers to do things that look intelligent.</p>
</li>
<li><p><strong>Machine learning (ML)</strong> lives inside AI: systems learn from data instead of hard-coded rules.</p>
</li>
<li><p><strong>Deep learning (DL)</strong> is a way for computers to learn patterns by practicing on a huge number of examples.</p>
</li>
<li><p><strong>NLP</strong> (natural language processing) is the part of AI that works with human language. As simple as that.</p>
</li>
<li><p><strong>Generative AI</strong> is the branch that <em>creates</em> new content (text, images, audio, code). Whatever it is, it just means it <strong>generates</strong> things rather than <strong>predicts</strong> things, as done with more classical AI systems.</p>
</li>
<li><p><strong>LLMs</strong> (Large Language Models) are deep learning models within the generative AI family that specialize in <strong>text generation</strong>.</p>
</li>
</ul>
<p>That’s all you need for now: AI → ML → DL → (NLP) → <strong>LLMs</strong>. With the labels straight, we can understand what an LLM actually does.</p>
<h3>What is an LLM?</h3>
<p>An LLM is a powerful autocomplete system. It’s a machine built to answer one simple question over and over again: “Given this sequence of text, what is the most probable next token?” That “piece of text” is called a <strong>token</strong>—it can be a word, a part of a word (like runn and ing), or punctuation.</p>
<p>For example, if a user asks ChatGPT, “What is fine-tuning?”, it doesn’t “know” the answer. It just predicts the next token, one at a time:</p>
<ol>
<li><p>The most probable first token is “<strong>Fine-tuning</strong>”.</p>
</li>
<li><p>Given that, the next most probable token is “<strong>is</strong>”.</p>
</li>
<li><p>Next is “<strong>the</strong>”, and so on...</p>
</li>
</ol>
<p>Until it generates a full sentence: “<strong>Fine-tuning is the process of training a pre-trained model further on a smaller, specific dataset.</strong>”</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/deb1b96a-707e-45fc-8ce3-b2dbb6d69038.webp" alt="" style="display:block;margin:0 auto" />

<p>It’s called a <strong>Large Language Model</strong> for three simple reasons:</p>
<ul>
<li><p><strong>Large</strong>: It has billions of internal variables (called <strong>parameters</strong>) and was trained on a massive amount of text.</p>
</li>
<li><p><strong>Language</strong>: It’s specialized for understanding and generating human language.</p>
</li>
<li><p><strong>Model</strong>: It’s a mathematical representation of the patterns it learned.</p>
</li>
</ul>
<p>So, at its heart, an LLM is just a very advanced guessing machine: predicting the next token again and again until a full answer appears. So, how does it get good at making those guesses in the first place?</p>
<p>To get there, the model undergoes a long study session of its own—a process called <strong>pre-training</strong>. For example, if a student is asked to read every book in a giant library (a huge slice of the internet, in the case of LLMs). They’re not trying to memorize pages word-for-word. Instead, they learn patterns—how words, sentences, and ideas fit together—well enough to predict the next piece of text in any sentence. This is how a base model like GPT-5 is built during pre-training.</p>
<p><a href="https://newsletter.systemdesign.one/p/llm-concepts?utm_source=publication-search">https://newsletter.systemdesign.one/p/llm-concepts?utm_source=publication-search</a></p>
<h2>AI Agents</h2>
<h3>AI Workflows</h3>
<p>AI workflows can be either non-agentic or agentic.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/4d4f0cb3-9922-4bd2-a0d1-b8e827fc012c.webp" alt="" style="display:block;margin:0 auto" />

<ol>
<li><p><strong>Non-Agentic Workflow:</strong> An LLM is given an instruction and produces a response. For example, in a question answering workflow, the input is a question, the LLM generates an answer, and the workflow returns that answer.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/01aa98ad-b728-42b5-a535-c8bb7b667e72.webp" alt="" style="display:block;margin:0 auto" />

<p>Even if you give the LLM an extra tool, the workflow is still non-agentic if it follows a fixed path and the LLM has no control over decisions or actions.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/e92f56c8-9026-4701-b824-374f37f994cc.webp" alt="" style="display:block;margin:0 auto" />
</li>
<li><p><strong>Agentic Workflow:</strong> An agentic workflow is a set of connected steps carried out by an agent or multiple agents to complete a task or goal. These workflows use key features of AI agents, such as reasoning, planning, tool use, and memory.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/5f38dc3a-952d-4598-8065-b276c9e998c6.webp" alt="" style="display:block;margin:0 auto" /></li>
</ol>
<p>Now let’s take a closer look at AI agents.</p>
<h3>AI Agents</h3>
<p>AI agents are systems that use LLMs for reasoning and decision-making, along with tools to interact with the real world. This allows them to handle complex tasks with minimal human input. Each agent is given a specific role and a certain level of autonomy to achieve its goal. They also have memory, which helps them learn from past actions and improve over time.</p>
<p><a href="https://newsletter.systemdesign.one/p/ai-agents-explained?utm_source=post-email-title&amp;publication_id=1511845&amp;post_id=183063799&amp;utm_campaign=email-post-title&amp;isFreemail=true&amp;r=2d5wj&amp;triedRedirect=true&amp;utm_medium=email">https://newsletter.systemdesign.one/p/ai-agents-explained</a></p>
<p><a href="https://substack.com/home/post/p-181466313?utm_source=substack&amp;utm_medium=email">https://substack.com/home/post/p-181466313</a></p>
<h3>Components of an AI Agent</h3>
<ol>
<li><p><strong>Reasoning:</strong> AI agents work well because they can reason step by step. This ability comes from the LLM (with a defined role and task) and supports two main functions: <strong>Planning</strong> and <strong>reflecting</strong>.</p>
</li>
<li><p><strong>Memory:</strong> Stores context and relevant information. <strong>Short-Term memory</strong> tracks the current interaction, while <strong>Long-Term memory</strong> holds past knowledge and experiences.</p>
</li>
<li><p><strong>Tools (vector search, web search, APIs, etc.):</strong> Extends the agent’s abilities beyond text generation, giving it access to external data, real-time information, or APIs.</p>
</li>
</ol>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/2ff79d82-3606-443c-a9d5-e55f815dc009.webp" alt="" style="display:block;margin:0 auto" />

<h3>Agentic Patterns</h3>
<p>These patterns enable agents to dynamically adapt, plan, and collaborate, ensuring that the system can handle complex, real-world tasks with precision and scalability.</p>
<ol>
<li><strong>Reflection</strong></li>
</ol>
<p>The reflection pattern is a self-feedback mechanism, enabling agents to iteratively evaluate and refine their outputs.</p>
<p>Reflection is especially useful for tasks like coding, where the agent may not succeed right away. For example, it can write code, test it, analyze any errors, and use that feedback to fix and improve the code until it works.</p>
<p>By critiquing its own work and learning from each step, the agent can improve without human help. These reflections can be saved in memory so the agent solves future problems faster and adapts to user needs over time.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/32a3ac9d-9ed4-4c50-9a9a-de9a7905b5e9.webp" alt="" style="display:block;margin:0 auto" />

<ol>
<li><strong>Tool Use</strong></li>
</ol>
<p>Agents interact with external tools like vector search, APIs, or web search to expand their capabilities.</p>
<p>This pattern allows agents to gather information, perform computations, and manipulate data beyond their pre-trained knowledge. By dynamically integrating tools into workflows, agents can adapt to complex tasks and provide more accurate and contextually relevant outputs.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/4f51c532-cfff-481d-ba63-8d814ce65437.webp" alt="" style="display:block;margin:0 auto" />

<ol>
<li><strong>ReAct</strong></li>
</ol>
<p>Reflection’s good. Tools are good. But when you let your agent think and act in <em>loops</em>, it gets even better.</p>
<p>That’s what the ReAct pattern is all about: <em>Reasoning + Acting</em>.</p>
<p>Instead of answering everything in one go, the model reasons step-by-step and adjusts its actions as it learns more.</p>
<p>Example:</p>
<ul>
<li><p>Goal: “Find the user’s recent invoices.”</p>
</li>
<li><p>Step 1: “Query payments database.”</p>
</li>
<li><p>Step 2: “Hmm, results are outdated. Better ask the user to confirm.”</p>
</li>
<li><p>Step 3: Adjust query, repeat.</p>
</li>
</ul>
<p>It’s not just responding — it’s navigating.</p>
<p>To make ReAct work, you’ll need three things:</p>
<ul>
<li><p>Tools (for taking action)</p>
</li>
<li><p>Memory (for keeping context)</p>
</li>
<li><p>A reasoning loop (to track progress)</p>
</li>
</ul>
<p>ReAct makes your agents flexible. Instead of sticking to a rigid script, they think through each step, adapt in real-time, and course-correct as new information comes in.</p>
<p>If you want to build anything beyond a quick one-off answer, this is the pattern you need.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/2df5b432-9394-40d5-9771-ca4e704a84fe.gif" alt="" style="display:block;margin:0 auto" />

<ol>
<li><strong>Planning</strong></li>
</ol>
<p>Planning is a key agentic pattern that enables agents to autonomously decompose complex tasks into smaller, manageable subtasks.</p>
<p>Planning works best when the path to the goal is unclear and flexibility is important. For example, to fix a software bug, an agent might first read the bug report, find the relevant code, list possible causes, and then choose a debugging method. If the first fix fails, it can adjust based on the new error.</p>
<p>This is useful for solving complex problems that require flexibility and multiple steps.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/b7168a02-02f6-44d1-b87c-3860abf95d3d.webp" alt="" style="display:block;margin:0 auto" />

<ol>
<li><strong>Multi-Agent</strong></li>
</ol>
<p>Multi-agent collaboration allows agents to specialize in different tasks and work in parallel. Agents share progress and results to keep the overall workflow efficient and consistent.</p>
<p>By breaking complex tasks into smaller parts and assigning them to different agents, this approach makes workflows more scalable and flexible. Each agent can use its own memory, tools, reflection, or planning, which supports dynamic and collaborative problem-solving.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/fb53825c-2fcb-4a2f-a1fd-430b3eb88730.webp" alt="" style="display:block;margin:0 auto" />

<h3>Benefits of Agentic Workflows</h3>
<ul>
<li><p><strong>Flexible and adaptable:</strong> Agentic workflows adjust to changing tasks and challenges. Unlike rule-based systems, they evolve based on task complexity and can be customized using different patterns.</p>
</li>
<li><p><strong>Efficiency Gains:</strong> Agentic workflows can automate repetitive tasks with high accuracy.</p>
</li>
<li><p><strong>Self-correcting and learning:</strong> Using feedback and memory, agents refine their actions over time. This leads to better performance with each use.</p>
</li>
<li><p><strong>Better at complex tasks:</strong> By breaking complex problems into smaller steps, agents handle complex tasks more effectively.</p>
</li>
</ul>
<h3>Challenges of Agentic Workflows</h3>
<ul>
<li><p><strong>Overkill for simple tasks:</strong> AI agents can create extra overhead when used for simple tasks, leading to unnecessary complexity and higher costs.</p>
</li>
<li><p><strong>Less predictable:</strong> More autonomy means more unpredictability. Without proper guardrails, agent outputs can become unreliable or hard to control.</p>
</li>
<li><p><strong>Ethical concerns:</strong> Not all decisions should be left to AI. Sensitive tasks need human oversight to avoid mistakes or harm.</p>
</li>
</ul>
<p>Agentic workflows are powerful, but they come with extra complexity and computation. Use them only when needed.</p>
<h2>Context Engineering vs Prompt Engineering</h2>
<h3><strong>Prompt Engineering</strong></h3>
<p><em>The “Static Script”.</em></p>
<p>If you’ve been working with LLMs, you already know Prompt Engineering. It’s the craft of writing effective instructions for a model, and for the past two years, it’s been the primary way developers have tried to improve AI output.</p>
<p>Think of an LLM as a talented improv actor:</p>
<p><strong>Prompt Engineering</strong> is the script you hand them before the curtain rises. It defines their character, the scene's tone, and the rules of engagement. A good script can make a significant difference in performance.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/318e4666-7952-45eb-a8bf-ddb96bad8ea3.webp" alt="" style="display:block;margin:0 auto" />

<p>The standard developer toolkit for prompt engineering includes:</p>
<ul>
<li><p><strong>Role Assignment</strong> – Setting the persona with instructions like <em>“You are an expert travel agent.”</em> This primes the model to use vocabulary and behaviors associated with that role.</p>
</li>
<li><p><strong>Few-Shot Examples</strong> – Providing input/output pairs demonstrating the exact format you want. For example, showing the model three examples of properly formatted JSON responses before asking it to generate one.</p>
</li>
<li><p><strong>Chain of Thought (CoT)</strong> – Instructions like <em>“Let’s think step by step”</em> that encourage the model to show its reasoning. This dramatically reduces errors in logic and math problems by forcing the model to “work through” the problem rather than jumping to an answer.</p>
</li>
<li><p><strong>Constraint Setting</strong> – Hard limits on output, like <em>“Limit your response to 50 words,</em>” or <em>“Respond only with valid JSON.”</em></p>
</li>
</ul>
<p>These techniques are valuable and worth mastering.</p>
<p>But they share a fundamental limitation that becomes apparent when you move from demos to production.</p>
<p><strong>The “Paris, Kentucky” Failure</strong></p>
<p>The limitation of Prompt Engineering is that it is <strong>static</strong>.</p>
<p>Let’s return to our travel agent. The user says: <em>“Book me a hotel in Paris for the DevOps conference.”</em></p>
<p>An agent relying only on prompt engineering sees the words “Paris” and “DevOps.” It has no access to external data, so it does what LLMs do when they lack information: it makes a <em>probabilistic guess</em>. There’s a Paris in France, sure, but there’s also a Paris in Kentucky, Texas, Tennessee, and several other states. Without additional context, the model has no way of knowing which one you mean.</p>
<p>The result?</p>
<p>Your user gets booked into the Best Western in Paris, Kentucky.</p>
<p>No amount of clever prompt phrasing can fix this. You could write <em>“Always book hotels in major international cities”</em>—but what about the user who actually wants Paris, Texas? The problem isn’t the prompt. The problem is that the model lacks three critical pieces of information:</p>
<ol>
<li><p>User lives in London (suggesting international travel is more likely)</p>
</li>
<li><p>DevOps conference this year is actually in Paris, France</p>
</li>
<li><p>The user’s company policy requires booking Marriott properties under €200/night</p>
</li>
</ol>
<p>This is where the paradigm shifts.</p>
<p>We need to move from optimizing static scripts to dynamically assembling the right information at runtime. We need Context Engineering.</p>
<p><a href="https://andrewships.substack.com/p/prompt-driven-development">https://andrewships.substack.com/p/prompt-driven-development</a></p>
<p><a href="https://newsletter.systemdesign.one/p/context-engineering-vs-prompt-engineering?utm_source=post-email-title&amp;publication_id=1511845&amp;post_id=188715439&amp;utm_campaign=email-post-title&amp;isFreemail=true&amp;r=2d5wj&amp;triedRedirect=true&amp;utm_medium=email">https://newsletter.systemdesign.one/p/context-engineering-vs-prompt-engineering</a></p>
<p><a href="https://addyo.substack.com/p/the-prompt-engineering-playbook-for">https://addyo.substack.com/p/the-prompt-engineering-playbook-for</a></p>
<p><a href="https://blog.bytebytego.com/p/a-guide-to-effective-prompt-engineering?utm_source=post-email-title&amp;publication_id=817132&amp;post_id=186800497&amp;utm_campaign=email-post-title&amp;isFreemail=true&amp;r=2d5wj&amp;triedRedirect=true&amp;utm_medium=email">https://blog.bytebytego.com/p/a-guide-to-effective-prompt-engineering</a></p>
<h3><strong>What is Context?</strong></h3>
<p><a href="https://newsletter.systemdesign.one/p/what-is-context-engineering?utm_source=substack&amp;utm_medium=email">https://newsletter.systemdesign.one/p/what-is-context-engineering</a></p>
<p>Before getting into techniques or frameworks, it helps to be clear about what “context” actually means.</p>
<p>When you send a message to an AI assistant, it doesn’t just see your latest question. It sees the information included with your message, such as system instructions that guide its behavior, relevant parts of the conversation so far, any examples you provide, and sometimes documents or tool outputs.</p>
<p>All of that together is the context.</p>
<p>This matters because the model lacks long-term memory as humans do. It cannot recall past conversations unless that information is included again. Each response is generated solely from the current context.</p>
<p>The model can pay attention to only a limited amount of text at once. This limit is often called the <strong>context window</strong>. Dumping more into that space often makes answers worse, not better.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/dc42c515-cecc-45a3-8669-aa233b28189d.webp" alt="" style="display:block;margin:0 auto" />

<p>Context engineering is about managing that working space.</p>
<p>The goal is not to give the model as much information as possible, but to give it the right information at the moment it needs to respond.</p>
<p><strong>Why does this matter for agents?</strong></p>
<p>This becomes more important when the AI is doing more than answering a single question.</p>
<p>A simple chatbot takes your question, replies, and stops. But more advanced AI systems, often called <strong>agents</strong>, work on tasks that unfold over many steps. They might search for information, read results, summarize what matters, and then decide what to do next.</p>
<p>Each step generates new information that is added to what the model sees next, such as search results, summaries, and intermediate notes. Over time, the context grows, and much of it becomes no longer relevant to the current step. This is called <strong>context rot</strong>, where useful information gets buried under outdated details.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/7e69c8b2-9edb-4c6b-8387-b9a4e4acaa8b.webp" alt="" style="display:block;margin:0 auto" />

<p>Agents often work well on focused tasks.</p>
<p>But when a task is broad and requires many steps, the quality can vary. As the context gets heavier, important details from earlier can get lost.</p>
<h3>The Anatomy of Context</h3>
<p>Understanding what causes context rot is the first step.</p>
<p>The next is knowing exactly what goes into the context window so you can control it.</p>
<p>When an AI generates a response, it is not just reacting to your last message. It is responding to a structured bundle of inputs. Each part plays a different role, but they all compete for the same limited space.</p>
<ol>
<li><strong>System Prompt and User Prompt</strong></li>
</ol>
<p>The <strong>system prompt</strong> determines the model's overall behavior.</p>
<p>It describes how the assistant should act, the rules it should follow, and the kinds of responses expected.</p>
<p>Most of the time, you do not see the system prompt directly. It’s defined by the product or application you are using. This is why two assistants built on the same underlying model can behave very differently.</p>
<p>For example, ChatGPT tends to answer politely, refuse certain requests, and format responses in predictable ways, even if you never explicitly asked it to do so.</p>
<p>The <strong>user prompt</strong> is your message.</p>
<p>This includes your current question and, in a chat setting, earlier messages that are still included.</p>
<p>Both are sent to the model together. The system prompt guides behavior, and the user prompt describes what to do right now.</p>
<p>If you are building an AI feature and you control the system prompt, the hard part is balance. If the instructions are too strict, the assistant can become brittle when something unexpected occurs. If they are too vague, responses become inconsistent.</p>
<p>A practical approach is to start minimal, test with real use cases, and add rules only when you see specific failures.</p>
<ol>
<li><strong>Examples</strong></li>
</ol>
<p>Sometimes the clearest way to guide an AI is to show it what you want.</p>
<p>Instead of writing a long list of rules, you can include one or two example inputs and the exact outputs you expect. This is often called <strong>few-shot prompting</strong>.</p>
<p>You have probably done this in ChatGPT without realizing it. If you say, “<em>Format it like this</em>,” and paste a sample answer, the model will usually follow the pattern.</p>
<p>Examples work because they remove ambiguity. They show tone, structure, and level of detail in a way that instructions often cannot.</p>
<p>The tradeoff is space. Examples take up room in the context window, so they need to earn their spot. A few well-chosen examples are usually better than a long list.</p>
<ol>
<li><strong>Message History</strong></li>
</ol>
<p>In a chat, the model can respond to follow-up questions because earlier messages remain in context.</p>
<p>For example, if you ask ChatGPT, “<em>What is the capital of France?</em>” and then ask, “<em>What is the population?</em>”, it can usually infer you still mean the capital you just discussed.</p>
<p>This works because the conversation so far acts like shared scratch paper. The model does not truly remember the earlier exchange. It is simply reading it again as part of the input.</p>
<p>The problem is that the message history grows over time. As more turns accumulate, older messages take up space even when they are no longer relevant. That can make the model less focused. It may repeat itself, follow outdated assumptions, or miss a detail that matters now.</p>
<p>Managing message history usually means keeping what is still relevant, summarizing what is settled, and letting the rest drop out of the active context.</p>
<ol>
<li><strong>Tools</strong></li>
</ol>
<p>On its own, an LLM can only generate text. Tools let it do more than that.</p>
<p>Tools allow an agent to search the web, read documents, run code, query databases, or interact with external systems. When a tool is used, the result is usually fed back into the context so the model can use it in the next step.</p>
<p>You have seen this in ChatGPT when it searches the web or analyzes a file you uploaded. The output becomes part of what the model sees before it responds.</p>
<p>Tools are powerful, but every tool call adds more text that competes for attention. If a tool returns too much information or in an unclear format, it can overwhelm the model rather than help it.</p>
<p>Good tool design keeps results focused and predictable. Clear names, narrow responsibilities, and concise outputs make it easier for the model to use tools effectively.</p>
<ol>
<li><strong>Data</strong></li>
</ol>
<p>Beyond messages and tools, agents often work with external data.</p>
<p>This can be a document you upload, an article you paste into the chat, or files the system can access. When that information is included, it becomes part of the context.</p>
<p>Large documents do not always behave the way you expect. The model may focus on the wrong section or miss details. This is often a context management problem, not carelessness.</p>
<p>Managing documents usually means breaking them into smaller pieces, pulling in what is relevant to the current step, and leaving the rest out of the active context until needed.</p>
<h3>Context Retrieval Strategies</h3>
<p>System instructions, examples, tools, and message history are the context in which you can write directly.</p>
<p>But often the most important information is not known in advance. It has to be retrieved during the task.</p>
<p>For example, if you ask ChatGPT a question about a PDF you uploaded, it needs to find the relevant section. If you ask it to search the web, it has to decide what to search for and which results matter.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/46dca6c2-efbc-4dba-ab76-4d0608f28596.webp" alt="" style="display:block;margin:0 auto" />

<p>How an agent retrieves and injects information is a major part of context engineering. There are two main approaches: <strong>loading everything upfront</strong>, or <strong>retrieving as you go</strong>.</p>
<ol>
<li><strong>Loading Upfront</strong></li>
</ol>
<p>The simplest approach is to retrieve relevant information before the model starts responding, then include it in the context all at once.</p>
<p>This is what happens when ChatGPT searches the web and then writes an answer using the results it just found. The model is not answering from memory. It is answering based on the information that was retrieved and added to its context.</p>
<p>This pattern is commonly called <a href="https://blog.bytebytego.com/p/how-agentic-rag-works?utm_source=post-email-title&amp;publication_id=817132&amp;post_id=191425992&amp;utm_campaign=email-post-title&amp;isFreemail=true&amp;r=2d5wj&amp;triedRedirect=true&amp;utm_medium=email">retrieval augmented generation (<strong>RAG</strong>)</a>.</p>
<p><a href="https://newsletter.systemdesign.one/p/how-rag-works">https://newsletter.systemdesign.one/p/how-rag-works</a></p>
<p>Loading upfront works well when the question is clear, and the agent can predict what information will be useful. The downside is that the agent makes an early retrieval decision and may stick with it.</p>
<p>If something important is missing or the task changes direction, it can be harder to correct course.</p>
<ol>
<li><strong>Just-in-Time Retrieval</strong></li>
</ol>
<p>Another approach is to retrieve information as the task unfolds.</p>
<p>Instead of loading everything at the start, the agent takes a step, looks at what it has learned so far, and retrieves more information only when needed. You can sometimes see this in ChatGPT when it searches, reads, refines the query, and searches again during longer tasks.</p>
<p>This keeps the context cleaner because only the information actually needed gets pulled in. The tradeoff is that it takes more steps and requires the agent to decide when to retrieve and when to stop.</p>
<p>A useful pattern within just-in-time retrieval is to start broad and then drill down. This specification is called <strong>Progressive Disclosure.</strong></p>
<p>Rather than loading full documents immediately, the agent may start with short snippets or summaries, identify what looks relevant, and pull in more detail only then.</p>
<p>This is how humans tackle research, too.</p>
<p>You do not read every article in a database. You scan titles, read abstracts of promising ones, and dive deep only into the sources that matter.</p>
<ol>
<li><strong>Hybrid Strategy</strong></li>
</ol>
<p>Fortunately, you don’t have to pick one or the other.</p>
<p>Many agents combine both approaches. They load a small amount of baseline information upfront, then retrieve more as needed.</p>
<p>You can see this in tools like ChatGPT. Some instructions and conversation history are already present, and additional information, such as search results or document excerpts, is pulled in based on what you ask.</p>
<p>For simpler use cases, loading upfront is often enough. As tasks get more complex and span multiple steps, retrieving as you go becomes more important.</p>
<p>The right choice depends on how predictable your agent’s information needs are.</p>
<h3>Techniques for Long-Horizon Tasks</h3>
<p>Retrieval helps an agent pull in the right information.</p>
<p>But some tasks create a different problem. They run long enough that the agent produces more text than can fit in the context window.</p>
<p>You may have seen this in ChatGPT during long conversations or research tasks. Early responses are clear, but after many steps, the answers can drift or repeat themselves, especially when you send very long instructions, like asking for help with entire code bases. Over a long task, the agent can encounter far more information than it can keep in working memory at once.</p>
<p>Larger context windows are not a complete solution. They can be slower and more expensive, and they still accumulate irrelevant information over time. A better approach is to actively manage what stays in context and preserve the important parts as the task grows.</p>
<p>Three techniques help with this:</p>
<ul>
<li><p><strong>compressing the context</strong> when it gets full,</p>
</li>
<li><p><strong>keeping external notes</strong>,</p>
</li>
<li><p><strong>splitting work across multiple agents</strong>.</p>
</li>
</ul>
<ol>
<li><strong>Compaction</strong></li>
</ol>
<p>When the context approaches its limit, one option is to compress what’s there.</p>
<p>The agent summarizes the conversation so far, keeping the essential information and discarding the rest. This compressed summary becomes the new starting point, and the conversation continues from there.</p>
<p>You may have noticed something like this in long ChatGPT conversations. After many messages, earlier details can fade. This often happens because older parts of the conversation are shortened or dropped to make room for new input.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/10115abc-38f3-4400-8e34-bc33aaadc85b.webp" alt="" style="display:block;margin:0 auto" />

<p>The hard part is deciding what to keep.</p>
<p>The goal, key constraints, open questions, and decisions that affect future steps should stay. Raw tool outputs that have already been used can usually go. Repeated back and forth that does not change the plan can go too.</p>
<p>There is always a risk of losing something that matters later. A common safeguard is to store important details outside the context before discarding them, so the agent can retrieve them if needed.</p>
<ol>
<li><strong>Structured Note Taking</strong></li>
</ol>
<p>Compaction occurs when you’re running out of space. Structured note-taking happens continuously.</p>
<p>As the agent works, it keeps a small set of notes outside the context window. These notes capture stable information, such as the goal, constraints, decisions made so far, and a short list of what remains.</p>
<p>You can see a user-level version of this idea in features like ChatGPT’s memory. If you tell it to remember something, that information can persist beyond a single conversation and be brought back when relevant.</p>
<p>This works well for tasks with checkpoints or tasks that span multiple sessions.</p>
<p>A coding agent might keep a checklist of completed steps. A support assistant might store user preferences so that it does not have to ask the same questions again.</p>
<ol>
<li><strong>Sub-Agent Architectures</strong></li>
</ol>
<p>Sometimes the best approach is to break a large task into pieces and assign each piece to a separate agent with its own context window.</p>
<p>In many research-style agent designs, a main agent coordinates the overall task, while sub-agents handle focused subtasks. A sub-agent explores one area in depth, then returns a short summary. The main agent keeps the summary and moves on without carrying all the raw details forward.</p>
<p>You can think of research features in tools like ChatGPT as an example of the kind of workflow where this pattern is useful.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/fcd05545-c22b-43e4-90f9-3e226c497591.webp" alt="" style="display:block;margin:0 auto" />

<p>This works well when subtasks can run independently or require deep exploration.</p>
<p>The tradeoff is complexity. Coordinating multiple agents is harder than managing a single one, so it is usually best to start with simpler techniques and add sub-agents when a single agent becomes overwhelmed.</p>
<h3>Choosing the Right Technique</h3>
<p>There’s no one-size-fits-all solution. The right approach depends on your “agent and your use case”. These rules of thumb can help:</p>
<ul>
<li><p><strong>Compaction</strong> works best for long, continuous conversations where context gradually accumulates.</p>
</li>
<li><p><strong>Structured notes</strong> work best for tasks with natural checkpoints or when information needs to persist across sessions.</p>
</li>
<li><p><strong>Sub-agents</strong> work best when subtasks can run in parallel or require deep, independent exploration.</p>
</li>
</ul>
<p>These techniques can be combined. Start with the simplest approach and add complexity as needed.</p>
<h3>Putting It All Together</h3>
<p>Context engineering is not a single technique.</p>
<p>It’s an approach to designing AI systems. At each step, you decide what goes into the model’s context, what stays out, and what gets compressed.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5fdebe1f1485f22e24b356b6/89ad427b-e456-4660-98e2-7c16f19cbc0d.webp" alt="" style="display:block;margin:0 auto" />

<p>The components we covered work together.</p>
<p>System prompts and examples shape behavior. Message history maintains continuity. Tools let the agent take actions. Data gives it information to work with. Retrieval strategies determine how and when that information gets loaded. For long-running tasks, compaction, external notes, and sub-agents help manage context that would otherwise overflow.</p>
<p>When something goes wrong, context is often the place to look. If the agent hallucinates, it might need better retrieval to ground its answers. If it picks the wrong tool, the tool descriptions might be unclear. If it loses track after many turns, the message history might need summarization.</p>
<p>A practical approach is to start simple.</p>
<p>Test with small tasks first. If it works, scale up. If it fails, identify what went wrong and address the specific issue.</p>
<h2>How Does Memory For AI Agents Work?</h2>
<p><a href="https://www.decodingai.com/p/how-does-memory-for-ai-agents-work">https://www.decodingai.com/p/how-does-memory-for-ai-agents-work</a></p>
<h3>AI Agent's Memory</h3>
<p>One year ago at ZTRON, we faced a challenge that many AI builders encounter: how do we give our agent access to the right information at the right time? Like most teams, we jumped straight into building a complex multimodal Retrieval-Augmented Generation (RAG) system. We built the whole suite: embeddings for text, embeddings for images, OCR, summarization, chunking, and multiple indexes.</p>
<p>Our ingestion pipeline became incredibly heavy. It introduced unnecessary complexity around scaling, monitoring, and maintenance. At query time, instead of a straight line from question to answer, our agent would zigzag through 10 to 20 retrieval steps, trying to gather the right context. The latency was terrible, costs were high, and debugging was a nightmare.</p>
<p>Then we realized something essential. Because we were building a vertical AI agent for a specific use case, our data wasn’t actually that big. Through virtual multi-tenancy and smart data siloing, we could retrieve relevant data with simple SQL queries and fit everything comfortably within modern context windows—around 65,000 tokens maximum, well within Gemini’s 1 million token input capacity.</p>
<p>We dropped the entire RAG layer in favor of Context-Augmented Generation (CAG) with smart context window engineering. Everything became faster, cheaper, and more reliable. This experience taught me that the fundamental challenge in building AI agents isn’t just about retrieval. It is about understanding how to architect memory systems that match your actual use case.</p>
<p>The core problem we are solving is the fundamental limitation of LLMs: their knowledge is vast but frozen in time. They are unable to learn by updating their weights after training, a problem known as “continual learning”. An LLM without memory is like an intern with amnesia. They might be brilliant, but they cannot recall previous conversations or learn from experience.</p>
<p>To overcome this, we use the context window as a form of “working memory.” However, keeping an entire conversation thread plus additional information in the context window is often unrealistic. Rising costs per turn and the “lost in the middle” problem—where models struggle to use information buried in the center of a long prompt limit this approach. While context windows are increasing, relying solely on them introduces noise and overhead.</p>
<p>Memory tools act as the solution. They provide agents with continuity, adaptability, and the ability to “learn” without retraining. When we first started building agents, working with 8k or 16k token limits forced us to engineer complex compression systems. Today, we have more breathing room, but the principles of organizing memory remain essential for performance.</p>
<p>In this article, we will explore:</p>
<ol>
<li><p>The four fundamental types of memory for AI agents.</p>
</li>
<li><p>A detailed look at long-term memory: Semantic, Episodic, and Procedural.</p>
</li>
<li><p>The trade-offs between storing memories as strings, entities, or knowledge graphs.</p>
</li>
<li><p>The complete memory cycle, from ingestion to inference.</p>
</li>
</ol>
<h3>The 4 Memory Types for AI Agents</h3>
<p>To build effective agents, we must distinguish between the different places information lives. We can borrow terms from biology and cognitive science to categorize these layers useful for engineering.</p>
<p>There are four distinct memory types based on their persistence and proximity to the model’s reasoning core.</p>
<ol>
<li><p><strong>Internal Knowledge:</strong> This is the static, pre-trained knowledge baked into the LLM’s weights. It is the best place to store general world knowledge—models know about whole books without needing them in the context window. However, this memory is frozen at the time of training.</p>
</li>
<li><p><strong>Context Window:</strong> This is the slice of information we pass to the LLM during a specific call. It acts as the RAM of the LLM. It is the only “reality” the model sees during inference.</p>
</li>
<li><p><strong>Short-Term Memory:</strong> This is the RAM of the entire agentic system. It contains the active context window plus recent interactions, conversation history, and details retrieved from long-term memory. We slice this short-term memory to create the context window for a single inference step. It is volatile and fast, simulating the feeling of “learning” during a session</p>
</li>
<li><p><strong>Long-Term Memory:</strong> This is the external, persistent storage system (disk) where an agent saves and retrieves information. This layer provides the personalization and context that internal knowledge lacks and short-term memory cannot retain <a href="https://decodingml.substack.com/p/memory-the-secret-sauce-of-ai-agents">[4]</a>.</p>
</li>
</ol>
<p>The dynamic between these layers creates the agent’s intelligence. First, part of the long-term memory is “retrieved” and brought into short-term memory. This retrieval pipeline queries different memory types in parallel. Next, we slice the short-term memory into an active context window through context engineering. Finally, during inference, the LLM uses its internal weights plus the active context window to generate output.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/219faf9c-01af-4b84-ae04-ef2d1a968f51.webp" alt="" style="display:block;margin:0 auto" />

<p>Another useful way to visualize this is by proximity to the LLM. Internal memory is intrinsic, while long-term memory is the furthest away, requiring specific retrieval mechanisms to become useful.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/bd4e6a52-1911-4233-969e-6f73aa58f083.webp" alt="" style="display:block;margin:0 auto" />

<p>Categorizing memory this way is critical for engineering. Internal knowledge handles general reasoning. Short-term memory manages the immediate task. Long-term memory handles personalization and continuity. No single layer can perform all three functions effectively. To better understand long-term memory, we can further apply cognitive science definitions to specific data types.</p>
<h2>MCP - A Deep Dive</h2>
<p><a href="https://portkey.ai/blog/understanding-mcp-authorization/?ref=dailydev">https://portkey.ai/blog/understanding-mcp-authorization/?ref=dailydev</a></p>
<p>In November 2024, Anthropic launched the Model Context Protocol (MCP) to fix this problem. This wasn’t just another developer tool. It aimed to tackle a key infrastructure issue in AI engineering.</p>
<p>The challenge?</p>
<p>Every AI application needs to connect to data sources. Until now, they had to build custom integrations from scratch. This approach creates a fragmented ecosystem that does not scale.</p>
<p>For example, the world isn’t frozen in time, but LLMs are…</p>
<p>If you want an AI to “monitor server logs,” you can’t feed it a file. You would have to build a data pipeline that polls an API every few seconds. Filter out noise, then push only the relevant anomalies into the AI’s context window. If the API changes its rate limits or response format, your entire agent breaks.</p>
<p>A better way to think of MCP is like a USB-C port.</p>
<p><strong>The Old Way (Before USB):</strong></p>
<p>If you bought a mouse, it had a PS/2 plug. A printer had a massive parallel port. A camera had a proprietary cable. If you wanted to connect these to a computer, the computer needed a specific physical port for each one.</p>
<img src="https://substackcdn.com/image/fetch/$s_!-9tm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3d3f117-ae5d-4bda-8f05-d7c5d9913c5c_1200x630.png" alt="" style="display:block;margin:0 auto" />

<blockquote>
<p>This is the “N×M” problem:</p>
<p>Each device maker had to figure out how to connect to each computer. So, computer makers had to create ports for every device.</p>
</blockquote>
<p><strong>The MCP Way (With USB-C):</strong></p>
<p>Now, everything uses a standard port.</p>
<ul>
<li><p>Computer (AI Model) needs one USB-C port. It doesn’t need to know if you are plugging in a hard drive or a microphone; it just speaks “USB.”</p>
</li>
<li><p>Device (Data Source) requires a USB-C port. It doesn’t need to know if it’s plugged into a Mac, a PC, or an iPad.</p>
</li>
</ul>
<img src="https://substackcdn.com/image/fetch/$s_!ZbTU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d3b9ca3-1d3f-4587-90bb-5079031caf69_1200x630.png" alt="" style="display:block;margin:0 auto" />

<blockquote>
<p>The result: you can plug anything into anything instantly.</p>
</blockquote>
<p>The analogy makes sense in theory. But to understand why MCP matters, you need to see how painful the current reality actually is…</p>
<h3>The Integration Complexity Problem</h3>
<p>Every AI assistant needs context to be useful:</p>
<p>Claude needs access to your codebase. ChatGPT may require your Google Drive files. Custom agents need database connections. But how do these AI systems actually get that context?</p>
<p>Traditionally, each connection requires a custom integration.</p>
<p>If you’re building an AI coding assistant, you need to:</p>
<ol>
<li><p>Write code to connect to the GitHub API.</p>
</li>
<li><p>Add authentication and security.</p>
</li>
<li><p>Create a way to change GitHub’s data format into a version that your AI can understand.</p>
</li>
<li><p>Handle rate limiting, errors, and edge cases.</p>
</li>
<li><p>Repeat this entire process for GitLab, Bitbucket, and every other source control system.</p>
</li>
</ol>
<p>This creates the N×M problem:</p>
<blockquote>
<p>‘N’ AI assistants multiplied by ‘M’ data sources equals N×M unique integrations that need to be built and maintained.</p>
</blockquote>
<p>When Cursor wants to add Notion support, they build it from scratch. When GitHub Copilot wants the same thing, they build it again. The engineering effort gets duplicated across every AI platform.</p>
<p>The traditional approaches have fundamental limitations:</p>
<p><strong>Static, build-time integration</strong>:</p>
<p>Integrations are hard-coded into applications. You can’t add a new data source without updating the application itself. This makes rapid experimentation impossible and forces users to wait for official support.</p>
<p><strong>Application-specific security implementations</strong>:</p>
<p>Every integration reinvents authentication, authorization, and data protection. This leads to inconsistent security models and increases the attack surface.</p>
<p><strong>No standard way to discover</strong>:</p>
<p>AI systems can’t find out what capabilities a data source has. Everything needs clear programming. This makes it hard to create agents that adapt. They can’t use the new tools on their own.</p>
<p>The result is a ‘broken’ ecosystem!</p>
<p>Innovation is stuck because of integration work. Users can access only the connections that application developers create. So that’s a mess.</p>
<p>Now let’s look at how MCP cleans it up…</p>
<hr />
<h3>How MCP Solves It</h3>
<p>MCP’s solution is straightforward: <em>define a single protocol that functions across all systems.</em></p>
<p>Instead of building N×M integrations, you build N clients (one per AI application) and M servers (one per data source). The total integration work drops from N×M to N+M.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/9eeb4ffd-08a7-47b5-9c6e-ba52ed977f24.webp" alt="" style="display:block;margin:0 auto" />

<p>When a new AI assistant wants to support all existing data sources, it just needs to implement the MCP client protocol once.</p>
<p>When a new data source wants to be available to all AI assistants, it just needs to implement the MCP server protocol once.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/a33375e3-6fdb-4717-b83e-756d8ef9727c.webp" alt="" style="display:block;margin:0 auto" />

<p>Two critical architectural features power this efficiency:</p>
<p><strong>1. Dynamic Capability Discovery</strong></p>
<p>In traditional integrations, the AI application must know the data source details in advance.</p>
<p>If the API changes, the application breaks…</p>
<p>MCP flips this. It uses a “handshake” model. When an AI connects to an MCP server, it asks, <em>“What can you do?”</em>.</p>
<p>The server returns a list of available resources and tools in real time.</p>
<blockquote>
<p>RESULT:</p>
<p>You can add a new tool to your database server, like a “Refund User” function. The AI agent finds it right away the next time it connects. You won’t need to change any code in the AI application.</p>
</blockquote>
<p><strong>2. Decoupling Intelligence from Data</strong></p>
<p>MCP separates the thinking system (AI model) from the knowing system (the data source).</p>
<ul>
<li><p><strong>For Data Teams:</strong> They can build robust, secure MCP servers for their internal APIs without worrying about which AI model will use them.</p>
</li>
<li><p><strong>For AI Teams:</strong> They can swap models without having to rebuild their data integrations.</p>
</li>
</ul>
<p>This decoupling means your infrastructure doesn’t become obsolete whenever a new AI model gets released.</p>
<p>You build your data layer once, and it works with whatever intelligence layer you choose to plug into it.</p>
<p>An AI agent using MCP doesn’t need to know in advance what tools are available. It simply connects, negotiates capabilities, and uses them as needed. This enables a level of flexibility and scale that is impossible with traditional static integrations.</p>
<p>The high-level concept is straightforward.</p>
<p>But the real elegance is in how the architecture actually works under the hood…</p>
<h3><strong>MCP Architecture Deep Dive</strong></h3>
<p>MCP’s architecture has three main layers.</p>
<p>These layers separate concerns and allow for easy scalability:</p>
<ol>
<li><strong>The Three-Layer Model</strong></li>
</ol>
<p><strong>Hosts</strong> are user-facing apps.</p>
<p>This includes the Claude Desktop app, IDEs like VSCode, or custom AI agents you create. Hosts are where users connect with the AI. They are also where requests begin. They do more than display the UI; they orchestrate the entire user experience.</p>
<p>The host application interprets the user’s prompt.</p>
<p>It decides whether external data or tools are needed to fulfill the request. If access is necessary, the host creates and manages several internal clients. It keeps one client for each MCP server it connects to.</p>
<p>The protocol layer handles the mechanics of data access.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/0e441a9c-de86-4646-8fe0-482fe51bb441.webp" alt="" style="display:block;margin:0 auto" />

<p><strong>Clients</strong> are protocol-speaking connection managers that run on hosts.</p>
<p>Each client maintains a dedicated 1:1 connection with a single MCP server. They serve as the translation layer.</p>
<p>They convert abstract AI requests from the host into clear MCP messages. These messages, like tools/call or resources/read, can be understood by the server. Clients do more than send messages. They manage the entire session lifecycle. This includes handling connection drops, reconnections, and state.</p>
<p>When a connection starts, the client takes charge of capability negotiation. It asks the server which tools, resources, and prompts it supports.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/66ef1e46-9ac1-4147-8150-d798e89de801.webp" alt="" style="display:block;margin:0 auto" />

<p><strong>Servers</strong> provide context.</p>
<p>They act as the layer that connects real-world systems, such as PostgreSQL databases, GitHub repositories, or Slack workspaces.</p>
<p>A server connects the MCP protocol to the data source. It translates MCP requests into the system’s native operations. For example, it turns an MCP read request into a SQL <code>SELECT</code> query. They are very flexible. They can run on a user’s machine for private access or remotely as a cloud service.</p>
<p>Servers share their available capabilities when connected. They inform the client about the Resources, Prompts, and Tools they offer.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/2e02df2f-daa9-4296-a092-73e1d48323f0.webp" alt="" style="display:block;margin:0 auto" />

<p><a href="https://newsletter.systemdesign.one/p/how-mcp-works?utm_source=post-email-title&amp;publication_id=1511845&amp;post_id=182336702&amp;utm_campaign=email-post-title&amp;isFreemail=true&amp;r=2d5wj&amp;triedRedirect=true&amp;utm_medium=email">https://newsletter.systemdesign.one/p/how-mcp-works</a></p>
<h2>AGENTS.MD</h2>
<p>An <code>AGENTS.md</code> file is a markdown file you check into Git that customizes how AI coding agents behave in your repository. It sits at the top of the conversation history, right below the system prompt.</p>
<p>Think of it as a configuration layer between the agent's base instructions and your actual codebase. The file can contain two types of guidance:</p>
<ul>
<li><p><strong>Personal scope</strong>: Your commit style preferences, coding patterns you prefer</p>
</li>
<li><p><strong>Project scope</strong>: What the project does, which package manager you use, your architecture decisions</p>
</li>
</ul>
<p>The <code>AGENTS.md</code> file is an open standard supported by many - though not all - tools.</p>
<h3>Why Massive AGENTS.MD Files Are a Problem</h3>
<p>There's a natural feedback loop that causes <code>AGENTS.md</code> files to grow dangerously large:</p>
<ol>
<li><p>The agent does something you don't like</p>
</li>
<li><p>You add a rule to prevent it</p>
</li>
<li><p>Repeat hundreds of times over months</p>
</li>
<li><p>File becomes a "ball of mud"</p>
</li>
</ol>
<p>Different developers add conflicting opinions. Nobody does a full style pass. The result? An unmaintainable mess that actually hurts agent performance.</p>
<p>Another culprit: auto-generated <code>AGENTS.md</code> files. Never use initialization scripts to auto-generate your <code>AGENTS.md</code>. They flood the file with things that are "useful for most scenarios" but would be better progressively disclosed. Generated files prioritize comprehensiveness over restraint.</p>
<p><strong>The Instruction Budget</strong></p>
<p>Kyle from Humanlayer's <a href="https://www.humanlayer.dev/blog/writing-a-good-claude-md"><strong>article</strong></a> mentions the concept of an "instruction budget":</p>
<blockquote>
<p><em><strong>Frontier thinking LLMs can follow ~ 150-200 instructions with reasonable consistency. Smaller models can attend to fewer instructions than larger models, and non-thinking models can attend to fewer instructions than thinking models.</strong></em></p>
</blockquote>
<p>Every token in your <code>AGENTS.md</code> file gets loaded on <strong>every single request</strong>, regardless of whether it's relevant. This creates a hard budget problem:</p>
<table>
<thead>
<tr>
<th><strong>Scenario</strong></th>
<th><strong>Impact</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Small, focused <code>AGENTS.md</code></td>
<td>More tokens available for task-specific instructions</td>
</tr>
<tr>
<td>Large, bloated <code>AGENTS.md</code></td>
<td>Fewer tokens for the actual work; agent gets confused</td>
</tr>
<tr>
<td>Irrelevant instructions</td>
<td>Token waste + agent distraction = worse performance</td>
</tr>
</tbody></table>
<p>Taken together, this means that <strong>the ideal</strong> <code>AGENTS.md</code> <strong>file should be as small as possible.</strong></p>
<p><strong>Stale Documentation Poisons Context</strong></p>
<p>Another issue for large <code>AGENTS.md</code> files is staleness.</p>
<p>Documentation goes out of date quickly. For human developers, stale docs are annoying, but the human usually has enough built-in memory to be skeptical about bad docs. For AI agents that read documentation on every request, stale information actively <em>poisons</em> the context.</p>
<p>This is especially dangerous when you document file system structure. File paths change constantly. If your <code>AGENTS.md</code> says "authentication logic lives in <code>src/auth/handlers.ts</code>" and that file gets renamed or moved, the agent will confidently look in the wrong place.</p>
<p>Instead of documenting structure, describe capabilities. Give hints about where things <em>might</em> be and the overall shape of the project. Let the agent generate its own just-in-time documentation during planning.</p>
<p>Domain concepts (like "organization" vs "group" vs "workspace") are more stable than file paths, so they're safer to document. But even these can drift in fast-moving AI-assisted codebases. Keep a light touch.</p>
<h3>Cutting Down Large AGENTS.md File</h3>
<p>Be ruthless about what goes here. Consider this the absolute minimum:</p>
<ul>
<li><p><strong>One-sentence project description</strong> (acts like a role-based prompt)</p>
</li>
<li><p><strong>Package manager</strong> (if not npm; or use <code>corepack</code> for warnings)</p>
</li>
<li><p><strong>Build/typecheck commands</strong> (if non-standard)</p>
</li>
</ul>
<p>That's honestly it. Everything else should go elsewhere.</p>
<p><strong>The One-Liner Project Description</strong></p>
<p>This single sentence gives the agent context about <em>why</em> they're working in this repository. It anchors every decision they make.</p>
<p>Example: This is a React component library for accessible data visualization.</p>
<p>That's the foundation. The agent now understands its scope.</p>
<p><strong>Package Manager Specification</strong></p>
<p>If you're In a JavaScript project and using anything other than npm, tell the agent explicitly:</p>
<p>This project uses pnpm workspaces.</p>
<p>Without this, the agent might default to <code>npm</code> and generate incorrect commands.</p>
<p><strong>Use Progressive Disclosure</strong></p>
<p>Instead of cramming everything into <code>AGENTS.md</code>, use <strong>progressive disclosure</strong>: give the agent only what it needs right now, and point it to other resources when needed.</p>
<p>Agents are fast at navigating documentation hierarchies. They understand context well enough to find what they need.</p>
<h4><strong>Move Language-Specific Rules to Separate Files</strong></h4>
<p>If your <code>AGENTS.md</code> currently says:</p>
<pre><code class="language-javascript">Always use const instead of let.
Never use var.
Use interface instead of type when possible.
Use strict null checks.
...
</code></pre>
<p>Move that to a separate file instead. In your root <code>AGENTS.md</code>:</p>
<pre><code class="language-javascript">For TypeScript conventions, see docs/TYPESCRIPT.md
</code></pre>
<p>Notice the light touch, no "always," no all-caps forcing. Just a conversational reference.</p>
<p>The benefits:</p>
<ul>
<li><p>TypeScript rules only load when the agent writes TypeScript</p>
</li>
<li><p>Other tasks (CSS debugging, dependency management) don't waste tokens</p>
</li>
<li><p>File stays focused and portable across model changes</p>
</li>
</ul>
<h4><strong>Nest Progressive Disclosure</strong></h4>
<p>You can go even deeper. Your <code>docs/TYPESCRIPT.md</code> can reference <code>docs/TESTING.md</code>. Create a discoverable resource tree:</p>
<pre><code class="language-javascript">docs/
├── TYPESCRIPT.md
│   └── references TESTING.md
├── TESTING.md
│   └── references specific test runners
└── BUILD.md
    └── references esbuild configuration
</code></pre>
<p>You can even link to external resources, Prisma docs, Next.js docs, etc. The agent will navigate these hierarchies efficiently.</p>
<h4><strong>Use Agent Skills</strong></h4>
<p>Many tools support "agent skills" - commands or workflows the agent can invoke to learn how to do something specific. These are another form of progressive disclosure: the agent pulls in knowledge only when needed.</p>
<h3>AGENTS.MD in Monorepos</h3>
<p>You're not limited to a single <code>AGENTS.md</code> at the root. You can place <code>AGENTS.md</code> files in subdirectories, and they <strong>merge with the root level</strong>.</p>
<p>This is powerful for monorepos:</p>
<p>What Goes Where:</p>
<table>
<thead>
<tr>
<th><strong>Level</strong></th>
<th><strong>Content</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>Root</strong></td>
<td>Monorepo purpose, how to navigate packages, shared tools (pnpm workspaces)</td>
</tr>
<tr>
<td><strong>Package</strong></td>
<td>Package purpose, specific tech stack, package-specific conventions</td>
</tr>
</tbody></table>
<p>Root <code>AGENTS.md</code>:</p>
<pre><code class="language-javascript">This is a monorepo containing web services and CLI tools.
Use pnpm workspaces to manage dependencies.
See each package's AGENTS.md for specific guidelines.
</code></pre>
<p>Package-level <code>AGENTS.md</code> (in <code>packages/api/AGENTS.md</code>):</p>
<pre><code class="language-javascript">This package is a Node.js GraphQL API using Prisma.
Follow docs/API_CONVENTIONS.md for API design patterns.
</code></pre>
<p><strong>Don't overload any level.</strong> The agent sees all merged <code>AGENTS.md</code> files in its context. Keep each level focused on what's relevant at that scope.</p>
<h3>Fix A Broken Agents.md with this prompt</h3>
<p>If you're starting to get nervous about the <code>AGENTS.md</code> file in your repo, and you want to refactor it to use progressive disclosure, try copy-pasting this prompt into your coding agent:</p>
<pre><code class="language-javascript">I want you to refactor my AGENTS.md file to follow progressive disclosure principles.

Follow these steps:

1. **Find contradictions**: Identify any instructions that conflict with each other. For each contradiction, ask me which version I want to keep.

2. **Identify the essentials**: Extract only what belongs in the root AGENTS.md:
   - One-sentence project description
   - Package manager (if not npm)
   - Non-standard build/typecheck commands
   - Anything truly relevant to every single task

3. **Group the rest**: Organize remaining instructions into logical categories (e.g., TypeScript conventions, testing patterns, API design, Git workflow). For each group, create a separate markdown file.

4. **Create the file structure**: Output:
   - A minimal root AGENTS.md with markdown links to the separate files
   - Each separate file with its relevant instructions
   - A suggested docs/ folder structure

5. **Flag for deletion**: Identify any instructions that are:
   - Redundant (the agent already knows this)
   - Too vague to be actionable
   - Overly obvious (like "write clean code")
</code></pre>
<h3>Don’t Build a Ball of Mud</h3>
<p>When you're about to add something to your <code>AGENTS.md</code>, ask yourself where it belongs:</p>
<table>
<thead>
<tr>
<th><strong>Location</strong></th>
<th><strong>When to use</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Root <code>AGENTS.md</code></td>
<td>Relevant to every single task in the repo</td>
</tr>
<tr>
<td>Separate file</td>
<td>Relevant to one domain (TypeScript, testing, etc.)</td>
</tr>
<tr>
<td>Nested documentation tree</td>
<td>Can be organized hierarchically</td>
</tr>
</tbody></table>
<p>The ideal <code>AGENTS.md</code> is small, focused, and points elsewhere. It gives the agent just enough context to start working, with breadcrumbs to more detailed guidance.</p>
<p>Everything else lives in progressive disclosure: separate files, nested <code>AGENTS.md</code> files, or skills.</p>
<p>This keeps your instruction budget efficient, your agent focused, and your setup future-proof as tools and best practices evolve.</p>
<h2>Agent Skills</h2>
<h3>What are the Claude Skills?</h3>
<p>Claude Skills, officially launched as "Agent Skills" in October 2024 and significantly expanded in December 2024, are modular capabilities that teach Claude how to perform specific tasks in a repeatable, specialized way.</p>
<p>Think of Skills as custom training modules. Instead of explaining the same process to Claude every single time ("Here's how our company formats PRDs" or "Here's how we analyze user data"), you package those instructions once into a Skill. From then on, Claude automatically recognizes when that Skill is relevant and applies it.</p>
<p><strong>The technical definition:</strong> Skills are folders containing instructions, scripts, and resources that Claude loads dynamically when needed to perform specialized tasks. They can include:</p>
<ul>
<li><p>Markdown files with instructions and procedures</p>
</li>
<li><p>Executable code for complex operations</p>
</li>
<li><p>Templates and examples</p>
</li>
<li><p>Domain-specific knowledge</p>
</li>
</ul>
<p><strong>The practical reality:</strong> Skills turn Claude from a general-purpose AI into a specialist that knows <em>your</em> workflows, <em>your</em> brand guidelines, <em>your</em> data analysis methods, and <em>your</em> organizational processes.</p>
<p><a href="https://resources.anthropic.com/hubfs/The-Complete-Guide-to-Building-Skill-for-Claude.pdf?hsLang=en">https://resources.anthropic.com/hubfs/The-Complete-Guide-to-Building-Skill-for-Claude.pdf?hsLang=en</a></p>
<h3>A Brief History: How Skills Evolved</h3>
<p>Understanding when and why Anthropic introduced Skills helps explain why this matters now:</p>
<p><strong>October 2024</strong>: Anthropic quietly launched Agent Skills as a beta feature. Initially, it was developer-focused—available through the API and Claude Code. The idea was simple: let developers package specialized capabilities that Claude could invoke when relevant.</p>
<p><strong>December 18, 2024</strong>: The major expansion. Anthropic made Skills available across claude.ai, introduced organization-wide management for Team and Enterprise plans, launched a Skills Directory with partner-built skills from companies like Notion, Figma, Canva, and Atlassian, and most importantly, published Agent Skills as an open standard at <a href="http://agentskills.io">agentskills.io</a>.</p>
<p><strong>January 2025</strong>: Skills became integrated with other Claude features like Memory, Extended Thinking, and the new Cowork agent. The Skills Directory expanded significantly, and custom skill creation became more accessible to non-technical users.</p>
<p><strong>Current State (January 2026)</strong>: Skills are now available to Pro, Max, Team, and Enterprise users. You can use pre-built Anthropic Skills (for Excel, PowerPoint, Word, PDFs), install partner Skills from the directory, or create custom Skills tailored to your exact workflows.</p>
<p>The evolution shows Anthropic's strategy: start with developers, prove the concept, then democratize it for everyone. And it's working.</p>
<h3>What Claude Skills do?</h3>
<ol>
<li><p><strong>Teach Claude ONCE, Benefit FOREVER (Zero Re-Explaining):</strong> Skills are instruction folders Claude loads automatically when relevant. Stop re-explaining your preferences, processes, and domain expertise in every single conversation. One folder = permanent memory of your workflow. Build in 15-30 minutes using the built-in skill-creator tool. Works for frontend design, research methodology, document creation, sprint planning, customer onboarding, and compliance workflows. Saves hours weekly across teams and individual users.</p>
</li>
<li><p><strong>Progressive Disclosure = Minimal Token Usage (3-Level System):</strong> The 3-level system is genius: Level 1 (YAML frontmatter) always stays in Claude's system prompt — just enough for Claude to know WHEN to activate. Level 2 (<a href="http://SKILL.md">SKILL.md</a> body) loads only when relevant. Level 3 (linked files) loads only as needed. Result: specialized expertise without bloating every conversation. Same AI power, fraction of the token cost. An estimated 50%+ reduction in tokens per workflow session versus re-prompting every chat. Keep SKILL.md under 5,000 words, move detailed docs to references/ folder</p>
</li>
<li><p><strong>One Skill = All Surfaces (100% Portability)</strong>: Build a skill ONCE, and it works identically on <a href="http://Claude.ai">Claude.ai</a>, Claude Code, and API — no modifications needed. This is unprecedented in AI tooling. Competitors lock you into one interface. Skills follow you everywhere. Deploy to individuals, teams, or your entire organization from one central folder. Organization-wide deployment launched December 18, 2025, with automatic updates and centralized admin management for enterprise teams.</p>
</li>
<li><p><strong>MCP + Skills = Your AI Employee (Kitchen Analogy)</strong>: MCP provides the professional kitchen: real-time access to Notion, Asana, Linear, Slack, GitHub, and Figma. Skills provide the recipes: step-by-step instructions optimized for YOUR workflow. Without Skills, MCP users get tool access but no workflow guidance — resulting in support tickets and inconsistent results. With Skills, pre-built workflows activate automatically. Anthropic data shows users blame the MCP connector when the real issue is missing workflow knowledge.</p>
</li>
<li><p><strong>5 Battle-Tested Patterns (Real-World Workflows)</strong>: Anthropic released 5 proven workflow patterns from early adopters: Pattern 1 (Sequential Workflow) for multi-step processes in exact order. Pattern 2 (Multi-MCP Coordination) for workflows spanning Figma, Drive, Linear, and Slack simultaneously. Pattern 3 (Iterative Refinement) for self-validating output loops. Pattern 4 (Context-Aware Tool Selection) for smart routing to the right tool. Pattern 5 (Domain-Specific Intelligence) for compliance, finance, and legal workflows with embedded rules.</p>
</li>
<li><p><strong>OPEN Standard = Platform-Independent (Like MCP)</strong>: Anthropic published Agent Skills as an OPEN standard. Like MCP, skills work across AI platforms — not locked to Claude. Early ecosystem adoption already underway. Partners from Asana, Atlassian, Canva, Figma, Sentry, and Zapier have published skills. The GitHub repo anthropics/skills contains production-ready skills you can customize TODAY instead of building from scratch. Community-built skills are multiplying fast — early publishers gain maximum visibility and downloads.</p>
</li>
<li><p><strong>Skill File Structure (15-Minute Setup)</strong>: A skill is JUST a folder with 4 possible items: SKILL.md (required — Markdown with YAML frontmatter), scripts/ (optional Python or Bash), references/ (optional docs loaded on demand), assets/ (optional templates and icons). Folder name MUST be kebab-case (sprint-planner, NOT Sprint Planner or sprint_planner). SKILL.md must be EXACTLY that spelling — case-sensitive. No README.md inside the skill folder. Start with just SKILL.md — that is the entire minimum viable skill.</p>
</li>
<li><p><strong>API Integration = Production-Scale Deployment (/v1/skills)</strong>: For production applications, the /v1/skills endpoint lets you manage skills programmatically. Add skills to Messages API requests via the container.skills parameter. Version control through Claude Console. Works with Claude Agent SDK for custom AI agents. Requires Code Execution Tool beta access. Use the API for production deployments, automated pipelines, and agent systems. Individual users should use Claude.ai. API skills unlock enterprise-grade AI workflow automation at unlimited scale.</p>
</li>
<li><p><strong>Trigger Optimization = 90%+ Auto-Activation Rate</strong>: The description field is EVERYTHING. Target: skill triggers on 90%+ of relevant queries automatically. Good descriptions include WHAT the skill does AND WHEN to use it with specific trigger phrases. Bad: "Helps with projects." Good: "Manages Linear sprint planning. Use when user mentions 'sprint', 'Linear tasks', or asks to 'create tickets'." Run 10-20 test queries. Ask Claude directly: "When would you use the [skill name] skill?" — Claude quotes your description back and reveals exactly what is missing.</p>
</li>
<li><p><strong>Organization-Wide Skills Deployment (December 2025)</strong>: Admins can now deploy skills workspace-wide — launched December 18, 2025. Automatic updates push to all users simultaneously. Centralized management from admin panel. One skill update standardizes EVERY team member's workflow instantly. No more inconsistent AI results between teammates who prompt differently. Companies building skills libraries NOW gain compounding efficiency advantages against competitors still re-explaining context every single chat session. This is the AI operations layer enterprises have been waiting for.</p>
</li>
</ol>
<h3>Why This Changes Everything</h3>
<ol>
<li><p><strong>The End of Prompt Engineering (Finally)</strong>: Prompt engineering required constant re-explanation, relied on individual memory, produced inconsistent results, and could not be shared easily. Skills are shareable, versioned, auto-activating, and organization-deployable. The shift is from art (crafting the perfect prompt) to engineering (building a reliable system). Early adopters building skills libraries NOW will have a 6-12 month workflow advantage over teams still copying prompts from Notion docs and Slack messages.</p>
</li>
<li><p><strong>Solves the "New Chat = New Explanation" Problem</strong>: Every new Claude conversation resets context completely. Skills eliminate this permanently. Claude loads your workflow automatically based on what you say — no explicit trigger needed. Power users currently spend 10-20% of their AI time re-establishing context every session. Skills compress that to near-zero. The compounding time savings across 1,000+ sessions per year is enormous — estimated 200+ hours annually per person recovered from pure context-setting overhead.</p>
</li>
<li><p><strong>Democratizes Expert AI Workflows</strong>: Previously, getting Claude to follow expert workflows required prompt engineering knowledge, time, and extensive trial-and-error. Skills democratize this: download a community-built skill from GitHub, upload to Claude.ai in 60 seconds, and instantly access workflows built by domain experts. A junior marketer can now operate with the same AI workflow sophistication as a senior AI engineer. The public skills marketplace is still early — first movers can publish skills that thousands of users download and benefit from.</p>
</li>
<li><p><strong>MCP Adoption Accelerator (Critical for Developers)</strong>: Without skills, MCP integrations face user abandonment: users connect the tool but don't know how to use it effectively. With skills, MCP becomes turnkey. Anthropic's research shows users blame the MCP connector when the real issue is missing workflow guidance. Skills fix this permanently. If you've built an MCP server, adding a companion skill dramatically increases user retention, reduces support tickets, and differentiates your product from the growing field of MCP-only competitors.</p>
</li>
<li><p><strong>Compounding Efficiency = Compounding Advantage</strong>: Every skill you build is a one-time investment that pays dividends indefinitely. Build a 30-minute skill today, save 5 minutes per workflow session. At 10 sessions per day = 50 minutes saved daily = 250 minutes per week = 200+ hours per year per person. Teams of 10 = 2,000+ hours annually recovered from a single well-built skill. Organizations building skills libraries systematically gain structural productivity advantages that compound over time against competitors still working session-by-session.</p>
</li>
</ol>
<h3>When something deserves to become a Skill</h3>
<p>The Skill doesn’t come first. What comes first is a pattern.</p>
<p>Every time I faced messy strategic notes, I was unconsciously applying the same mental structure:</p>
<p>Clarify the context → Extract key signals → Surface risks → Compare trade-offs → Present structured options → Define next steps</p>
<p>That repetition is what changed everything.</p>
<p>Because repetition is the signal that something deserves structure.</p>
<p>Here are the problems I had before using skills (and what they led to):</p>
<ul>
<li><p>No defined role → Inconsistent responses</p>
</li>
<li><p>No rules → Shifts in tone</p>
</li>
<li><p>No boundaries → Unnecessary creative drift</p>
</li>
<li><p>No environment → Constant repetition</p>
</li>
</ul>
<p>That shift didn’t happen because I created a Skill. It happened because I stopped improvising.</p>
<p>Structure came first. Automation came second.</p>
<p>The hidden step most people skip can be summarized like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/2c126e9f-326f-4b1f-92d6-f76734af2a6b.webp" alt="" style="display:block;margin:0 auto" />

<p>The difference is massive. In the first case (left side), you automate an idea. In the second case (right side), you automate a proven framework.</p>
<p>A Skill is not a clever idea. It is a structure that has already proven it works multiple times.</p>
<h3>Skills vs. Other Claude Features: What's the Difference?</h3>
<p>Claude has several features that sound similar. Here's how they differ:</p>
<p><strong>Skills vs. Projects:</strong></p>
<ul>
<li><p><strong>Projects</strong> provide static background context that's always loaded when you're in that project</p>
</li>
<li><p><strong>Skills</strong> provide dynamic procedures that only load when relevant</p>
</li>
<li><p>Use Projects for persistent knowledge, Skills for repeatable processes</p>
</li>
</ul>
<p><strong>Skills vs. Custom Instructions:</strong></p>
<ul>
<li><p><strong>Custom Instructions</strong> apply broadly to all your conversations</p>
</li>
<li><p><strong>Skills</strong> are task-specific and only activate when needed</p>
</li>
<li><p>Custom Instructions set general preferences; Skills provide specialized procedures</p>
</li>
</ul>
<p><strong>Skills vs. MCP Connectors:</strong></p>
<ul>
<li><p><strong>MCP Connectors</strong> give Claude access to external tools and data (like Notion, Slack)</p>
</li>
<li><p><strong>Skills</strong> teach Claude how to use those tools effectively</p>
</li>
<li><p>They work together: MCP provides access, Skills provide process</p>
</li>
</ul>
<p><strong>Example</strong>: An MCP connector gives Claude access to your Notion workspace. A Skill teaches Claude how to format meeting notes according to your team's specific template within Notion.</p>
<h3>Potential Drawbacks and Limitations</h3>
<p>Let's be honest about where Skills fall short:</p>
<p><strong>1. Requires Code Execution to be Enabled</strong><br />Skills use Claude's code execution capability. If you've disabled this for security reasons, Skills won't work. This is a consideration for enterprises with strict security policies.</p>
<p><strong>2. Initial Setup Time</strong><br />Creating good Skills takes time. You need to document processes clearly, provide examples, and iterate based on results. The ROI is there, but it's not instant.</p>
<p><strong>3. Not Ideal for Highly Dynamic Processes</strong><br />If your workflow changes constantly, maintaining Skills becomes overhead. They're best for processes that are reasonably stable.</p>
<p><strong>4. Potential for Over-Reliance</strong><br />There's a risk that teams become dependent on Skills without understanding the underlying processes. Junior PMs might use a "Feature Spec" Skill without learning what makes a good spec.</p>
<p><strong>5. Quality Depends on Quality of Instructions</strong><br />Garbage in, garbage out. Poorly written Skill instructions produce inconsistent results. This requires thoughtful documentation.</p>
<p><strong>6. Limited to Available Plans</strong><br />Skills are only available on Pro, Max, Team, and Enterprise plans. Free-tier users can't access them.</p>
<h3>Finding &amp; Installing Third-Party Skills</h3>
<ol>
<li><strong>Official Anthropic Repositories</strong></li>
</ol>
<p><a href="https://github.com/anthropics/skills">github.com/anthropics/skills</a> → Official skill examples + production document skills (docx, pdf, pptx, xlsx). Apache 2.0 for examples; source-available for doc skills. Functions as a Claude Code Plugin marketplace.</p>
<p><a href="https://github.com/anthropics/claude-plugins-official">github.com/anthropics/claude-plugins-official</a> → Official plugin marketplace directory. Third-party partners can submit.</p>
<p><a href="https://github.com/anthropics/knowledge-work-plugins">github.com/anthropics/knowledge-work-plugins</a> → 11 role-based plugins (Sales, Support, Product Management, Finance, Data, etc.) with skills, commands, and MCP connectors. Open source.</p>
<p><a href="https://github.com/anthropics/life-sciences">github.com/anthropics/life-sciences</a> → Life sciences MCP servers and skills (PubMed, BioRender, etc.)</p>
<ol>
<li><strong>Community Skill Directories &amp; Marketplaces</strong></li>
</ol>
<p><a href="http://skills.sh">skills.sh</a> → Primary distribution hub. npx skills add . Leaderboard, multi-platform.</p>
<p><a href="http://skillsmp.com">skillsmp.com</a> → Independent directory, aggregates from GitHub. Min 2-star filter.</p>
<p><a href="http://skillhub.club">skillhub.club</a> → 20K+ skills with AI-evaluated quality ratings. Has a playground.</p>
<p><a href="http://hub.skild.sh">hub.skild.sh</a> → Another community registry</p>
<p><a href="http://agentskill.sh">agentskill.sh</a> → 25K+ skills directory, browseable by category/platform</p>
<ol>
<li><strong>Key Community Projects</strong></li>
</ol>
<p><a href="https://github.com/obra/superpowers">obra/superpowers</a> → Complete software dev workflow: brainstorm → plan → TDD → implement → review. 20+ battle-tested skills. The gold standard for skill composition. Install: /plugin marketplace add obra/superpowers-marketplace then /plugin install superpowers@superpowers-marketplace</p>
<p><a href="https://github.com/obra/superpowers-skills">obra/superpowers-skills</a> → Community-editable extension to Superpowers</p>
<p><a href="https://github.com/obra/superpowers-lab">obra/superpowers-lab</a> → Experimental skills (tmux for interactive commands, etc.)</p>
<p><a href="https://github.com/travisvn/awesome-claude-skills">travisvn/awesome-claude-skills</a> → Curated awesome-list of skills, resources, and tools</p>
<p><a href="https://github.com/numman-ali/openskills">numman-ali/openskills</a> → Universal skills loader. npx openskills install anthropics/skills. Works across Claude Code, Cursor, Windsurf, Aider, Codex, etc.</p>
<p><a href="https://github.com/vercel-labs/agent-skills">vercel-labs/agent-skills</a> → Vercel’s official skills: React, Next.js, React Native patterns + Vercel deploy skill</p>
<p><a href="https://github.com/qufei1993/skills-hub">qufei1993/skills-hub</a> → Desktop app: “Install once, sync everywhere” — manages skills across multiple AI tools</p>
<p><a href="http://inference.sh">inference.sh</a> <a href="https://inference.sh/blog/skills/agent-skills-overview">skills</a> → 150+ cloud AI app skills (image gen, video, TTS, search) via infsh CLI</p>
<h3>Building Your Own Skills — Best Practices</h3>
<p><strong>Design Principles</strong></p>
<ol>
<li><p><strong>Single-purpose</strong>: “SEO optimization for blog posts” is good. “Content marketing helper” is too broad. “Add meta descriptions” is too narrow.</p>
</li>
<li><p><strong>Description is king</strong>: Claude routes based on the <code>description</code> field. Vague = missed triggers. Overly generic = false triggers. Be specific about <em>when</em> and <em>what</em>.</p>
</li>
<li><p><strong>Progressive disclosure</strong>: Keep SKILL.md lean. Reference files for deep details. Scripts for deterministic steps.</p>
</li>
<li><p><strong>Imperative instructions</strong>: Write as if onboarding a smart junior engineer. Be explicit about steps, inputs, outputs.</p>
</li>
<li><p><strong>Include examples</strong>: Show expected inputs and outputs. Show what “good” looks like.</p>
</li>
<li><p><strong>Token budget</strong>: Metadata ~50-100 tokens. Full SKILL.md &lt; 5000 tokens. Reference files on-demand.</p>
</li>
</ol>
<p><strong>The Description Field — Most Important 200 Characters You’ll Write</strong></p>
<p>Bad:</p>
<p>yaml</p>
<pre><code class="language-plaintext">description: Helps with code
</code></pre>
<p>Good:</p>
<p>yaml</p>
<pre><code class="language-plaintext">description: &gt;-
  Generate FastAPI backend with React+Vite frontend, Tailwind, shadcn/ui,
  and OpenAI integration. Use when asked to scaffold a full-stack AI app.
</code></pre>
<p>Claude uses <strong>semantic matching</strong>, not keyword matching — but vague descriptions still reduce accuracy.</p>
<p><strong>Skill Structure Patterns</strong></p>
<p><strong>Pattern 1: Instructions-only</strong> (simplest)</p>
<pre><code class="language-plaintext">my-skill/
└── SKILL.md     # All instructions in one file
</code></pre>
<p><strong>Pattern 2: Instructions + References</strong></p>
<pre><code class="language-plaintext">brand-guidelines/
├── SKILL.md           # Overview + when to apply
└── references/
    ├── colors.md      # Detailed color specs
    ├── typography.md   # Font rules
    └── voice.md       # Tone of voice guide
</code></pre>
<p><strong>Pattern 3: Instructions + Scripts</strong> (executable)</p>
<pre><code class="language-plaintext">data-pipeline/
├── SKILL.md
├── scripts/
│   ├── validate.py
│   └── transform.sh
└── templates/
    └── output-schema.json
</code></pre>
<p><strong>Pattern 4: Full production skill</strong> (like the built-in docx skill)</p>
<pre><code class="language-plaintext">docx/
├── SKILL.md
├── LICENSE.txt
├── scripts/
│   ├── office/
│   │   ├── soffice.py
│   │   ├── unpack.py
│   │   └── validate.py
│   └── accept_changes.py
├── references/
│   └── REFERENCE.md
└── examples/
    └── sample-doc.docx
</code></pre>
<p><strong>Creating Skills with the Skill-Creator</strong></p>
<p>Claude has a built-in <code>skill-creator</code> skill (available in claude.ai and as a plugin). The workflow:</p>
<ol>
<li><p>Tell Claude “I want to create a skill for X”</p>
</li>
<li><p>It interviews you about the workflow</p>
</li>
<li><p>Generates the SKILL.md and folder structure</p>
</li>
<li><p>Creates test prompts</p>
</li>
<li><p>Runs Claude-with-skill on them</p>
</li>
<li><p>You evaluate results</p>
</li>
<li><p>Iterate until satisfied</p>
</li>
</ol>
<p>You can also use the eval/benchmark system for more rigorous testing:</p>
<ul>
<li><p><strong>Eval mode</strong>: Test individual prompts, compare with/without skill</p>
</li>
<li><p><strong>Improve mode</strong>: Iterative optimization with blind A/B comparisons</p>
</li>
<li><p><strong>Benchmark mode</strong>: Standardized measurement with variance analysis (3x runs per config)</p>
</li>
</ul>
<p><strong>Claude Code-Specific Features</strong></p>
<p>In Claude Code, skills gain extra powers via frontmatter:</p>
<p>yaml</p>
<pre><code class="language-plaintext">---
name: deep-research
description: Research a topic thoroughly
context: fork          # Runs in a forked subagent
agent: Explore         # Uses the Explore agent (read-only tools)
---
</code></pre>
<p>Options for <code>context</code>:</p>
<ul>
<li><p>Default (omitted): Claude loads it when relevant</p>
</li>
<li><p><code>fork</code>: Runs as a separate subagent task</p>
</li>
</ul>
<p>Options for <code>agent</code>:</p>
<ul>
<li><p><code>Explore</code>: Read-only codebase exploration</p>
</li>
<li><p><code>Plan</code>: Planning-focused</p>
</li>
<li><p>Custom: Any subagent from <code>.claude/agents/</code></p>
</li>
</ul>
<p>Skills can also be invoked as slash commands:</p>
<ul>
<li><p><code>.claude/skills/review/SKILL.md</code> creates <code>/review</code></p>
</li>
<li><p>(This replaced the older <code>.claude/commands/</code> system)</p>
</li>
</ul>
<h3>Getting-Up-To-Speed - Practical Plan</h3>
<p>Here I outline a practical approach on how to multiply your productivity by integrating agentic skills into your day-to-day workflow with Claude, Codex, or any other AI agent tool of your choice (using Claude as an example).</p>
<ol>
<li><strong>Foundation (2-3 hours)</strong></li>
</ol>
<p><strong>Understand the landscape</strong></p>
<ul>
<li><p>Read the <a href="https://agentskills.io/specification">Agent Skills specification</a> (15 min)</p>
</li>
<li><p>Read Anthropic’s <a href="https://claude.com/blog/skills">blog post introducing skills</a> (10 min)</p>
</li>
<li><p>Read the <a href="https://claude.com/blog/how-to-create-skills-key-steps-limitations-and-examples">how to create skills guide</a> (15 min)</p>
</li>
<li><p>Read the <a href="https://code.claude.com/docs/en/skills">Claude Code skills docs</a> (15 min)</p>
</li>
<li><p>Read Lee Han Chung’s <a href="https://leehanchung.github.io/blogs/2025/10/26/claude-skills-deep-dive/">deep dive on skill architecture</a> (20 min)</p>
</li>
</ul>
<p><strong>Explore existing skills</strong></p>
<ul>
<li><p>Browse <a href="https://github.com/anthropics/skills">github.com/anthropics/skills</a> — read 3-4 example <a href="http://SKILL.md">SKILL.md</a> files to see patterns</p>
</li>
<li><p>Browse <a href="http://skills.sh">skills.sh</a> and <a href="http://skillsmp.com">skillsmp.com</a> to see what the community has built</p>
</li>
<li><p>Install Superpowers in Claude Code: <code>/plugin marketplace add obra/superpowers-marketplace</code> + <code>/plugin install superpowers@superpowers-marketplace</code></p>
</li>
<li><p>Read <a href="https://blog.fsck.com/2025/10/09/superpowers/">Jesse Vincent’s blog post on Superpowers</a> — this is the best practical write-up on skill composition</p>
</li>
<li><p>Browse <a href="https://github.com/travisvn/awesome-claude-skills">travisvn/awesome-claude-skills</a> for curated resources</p>
</li>
</ul>
<p><strong>Try it hands-on</strong></p>
<ul>
<li><p>Ask Claude (in <a href="http://claude.ai">claude.ai</a> or Claude Code) to “create a skill for [something you do repeatedly]” — use the skill-creator</p>
</li>
<li><p>Test the generated skill on a real task</p>
</li>
<li><p>Iterate once or twice based on results</p>
</li>
</ul>
<ol>
<li><strong>Build Your System (3-4 hours)</strong></li>
</ol>
<p><strong>Set up your skills infrastructure</strong></p>
<ul>
<li><p>Create a GitHub repo for your personal skills (<code>your-username/claude-skills</code>)</p>
</li>
<li><p>Add a <code>marketplace.json</code> to make it a Claude Code marketplace</p>
</li>
<li><p>Set up Obsidian vault with the Skills/ and Workflows/ structure described above</p>
</li>
<li><p>Install the Obsidian Git plugin and connect to your skills repo</p>
</li>
<li><p>Create a <a href="http://SKILL.md">SKILL.md</a> template in Obsidian Templater</p>
</li>
</ul>
<p><strong>Build your first 3 skills</strong> Start with workflows you repeat across projects:</p>
<ol>
<li><p><strong>Your project scaffolding workflow</strong> — how you set up a new project (tech stack, folder structure, CI, etc.)</p>
</li>
<li><p><strong>Your code review checklist</strong> — your standards for reviewing code</p>
</li>
<li><p><strong>Your product spec process</strong> — how you go from idea to spec</p>
</li>
</ol>
<p>For each:</p>
<ol>
<li><p>Document the workflow in Obsidian Workflows/</p>
</li>
<li><p>Draft the <a href="http://SKILL.md">SKILL.md</a></p>
</li>
<li><p>Push to Git</p>
</li>
<li><p>Register your marketplace in Claude Code</p>
</li>
<li><p>Test on a real task</p>
</li>
<li><p>Iterate</p>
</li>
</ol>
<p><strong>Day 5: Explore the API surface</strong></p>
<ul>
<li><p>Read the <a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview">Skills API docs</a></p>
</li>
<li><p>Try uploading a custom skill via the API</p>
</li>
<li><p>Understand the <code>/v1/skills</code> endpoints for programmatic management</p>
</li>
</ul>
<ol>
<li><strong>Scale &amp; Parallelize (3-4 hours)</strong></li>
</ol>
<p><strong>Build product-specific skills</strong> For each of your product ideas, create:</p>
<ul>
<li><p>Domain knowledge skill (what this product does, its entities, its terminology)</p>
</li>
<li><p>Architecture skill (your preferred stack, patterns, conventions for this product)</p>
</li>
<li><p>Testing skill (how you want tests structured for this product)</p>
</li>
</ul>
<p><strong>Explore advanced patterns</strong></p>
<ul>
<li><p>Read the <a href="https://github.com/anthropics/skills/tree/main/skills/mcp-builder">MCP builder skill</a> — skills + MCP is a powerful combination</p>
</li>
<li><p>Try <code>context: fork</code> and subagent delegation in Claude Code</p>
</li>
<li><p>Explore <a href="https://github.com/anthropics/knowledge-work-plugins">anthropics/knowledge-work-plugins</a> for the plugin architecture pattern</p>
</li>
<li><p>Install <code>openskills</code> (<code>npx openskills install anthropics/skills</code>) for cross-tool skill management</p>
</li>
</ul>
<p><strong>Automate and refine</strong></p>
<ul>
<li><p>Set up GitHub Actions to validate your skills on push (use <code>skills-ref</code> Python library)</p>
</li>
<li><p>Create a “meta-skill” that helps you create new skills faster (or use the built-in skill-creator as a base)</p>
</li>
<li><p>Document your skills system in your Obsidian vault so future-you (and future-Claude) can maintain it</p>
</li>
</ul>
<p><a href="https://codeagentsalpha.substack.com/p/claude-agent-skills-complete-getting?utm_source=%2Fsearch%2Fskills&amp;utm_medium=reader2">https://codeagentsalpha.substack.com/p/claude-agent-skills-complete-getting</a></p>
<p><a href="https://sifuyik.substack.com/p/anthropic-dropped-the-32-page-internal">https://sifuyik.substack.com/p/anthropic-dropped-the-32-page-internal</a></p>
<p><a href="https://artificialcorner.com/p/claude-code-skills">https://artificialcorner.com/p/claude-code-skills</a></p>
<p><a href="https://medium.com/product-powerhouse/claude-skills-the-ai-feature-thats-quietly-changing-how-product-managers-work-aad5d8d0640a">https://medium.com/product-powerhouse/claude-skills-the-ai-feature-thats-quietly-changing-how-product-managers-work-aad5d8d0640a</a></p>
<p><a href="https://www.youngleaders.tech/p/claude-skills-commands-subagents-plugins?utm_source=%2Fsearch%2Fskills&amp;utm_medium=reader2">https://www.youngleaders.tech/p/claude-skills-commands-subagents-plugins</a></p>
<p><a href="https://aiblewmymind.substack.com/p/claude-skills-36-examples">https://aiblewmymind.substack.com/p/claude-skills-36-examples</a></p>
<p><a href="https://medium.com/@mohit15856/i-tested-anthropics-skill-creator-plugin-on-my-own-skills-here-s-what-i-found-23ad406b0825">https://medium.com/@mohit15856/i-tested-anthropics-skill-creator-plugin-on-my-own-skills-here-s-what-i-found-23ad406b0825</a></p>
<h2>Spec-Driven Development</h2>
<p>Like with many emerging terms in this fast-paced space, the definition of “spec-driven development” (SDD) is still in flux. Here’s what I can gather from how I have seen it used so far: Spec-driven development means writing a “spec” before writing code with AI (“documentation first”). The spec becomes the source of truth for the human and the AI.</p>
<p><a href="https://github.com/github/spec-kit/blob/main/spec-driven.md">GitHub</a>: “In this new world, <em>maintaining software means evolving specifications</em>. […] The lingua franca of development moves to a higher level, and code is the last-mile approach.”</p>
<p><a href="https://docs.tessl.io/introduction-to-tessl/concepts">Tessl</a>: “A development approach where <em>specs — not code — are the primary artifact</em>. Specs describe intent in structured, testable language, and agents generate code to match them.”</p>
<p>After looking over the usages of the term, and some of the tools that claim to be implementing SDD, it seems to me that in reality, there are multiple implementation levels to it:</p>
<ol>
<li><p><strong>Spec-first</strong>: A well thought-out spec is written first, and then used in the AI-assisted development workflow for the task at hand.</p>
</li>
<li><p><strong>Spec-anchored</strong>: The spec is kept even after the task is complete, to continue using it for evolution and maintenance of the respective feature.</p>
</li>
<li><p><strong>Spec-as-source</strong>: The spec is the main source file over time, and only the spec is edited by the human, the human never touches the code.</p>
</li>
</ol>
<p>All SDD approaches and definitions I’ve found are spec-first, but not all strive to be spec-anchored or spec-as-source. And often it’s left vague or totally open what the spec maintenance strategy over time is meant to be.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/fce33fa7-9acc-4289-9af9-0bec87591ef5.png" alt="" style="display:block;margin:0 auto" />

<h3>What Is Spec-Driven Development?</h3>
<p>The key question in terms of definitions of course is: What is a spec? There doesn’t seem to be a general definition, the closest I’ve seen to a consistent definition is the comparison of a spec to a “Product Requirements Document”.</p>
<p>The term is quite overloaded at the moment, here is my attempt at defining what a spec is:</p>
<p>A spec is a structured, behavior-oriented artifact - or a set of related artifacts - written in natural language that expresses software functionality and serves as guidance to AI coding agents. Each variant of spec-driven development defines their approach to a spec’s structure, level of detail, and how these artifacts are organized within a project.</p>
<p>There is a useful difference to be made I think between specs and the more general context documents for a codebase. That general context are things like rules files, or high level descriptions of the product and the codebase. Some tools call this context a <a href="https://docs.cline.bot/prompting/cline-memory-bank"><strong>memory bank</strong></a>, so that’s what I will use here. These files are relevant across all AI coding sessions in the codebase, whereas specs only relevant to the tasks that actually create or change that particular functionality.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/76c00253-22ed-4613-924a-e633336a7f8f.png" alt="" style="display:block;margin:0 auto" />

<h3>The challenge with evaluating SDD tools</h3>
<p>It turns out to be quite time-consuming to evaluate SDD tools and approaches in a way that gets close to real usage. You would have to try them out with different sizes of problems, greenfield, brownfield, and really take the time to review and revise the intermediate artifacts with more than just a cursory glance. Because as <a href="https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/">GitHub’s blog post about spec-kit</a> says: “Crucially, your role isn’t just to steer. It’s to verify. At each phase, you reflect and refine.”</p>
<p>For two of the three tools I tried it also seems to be even more work to introduce them into an existing codebase, therefore making it even harder to evaluate their usefulness for brownfield codebases. Until I hear usage reports from people using them for a period of time on a “real” codebase, I still have a lot of open questions about how this works in real life.</p>
<p>That being said - let’s get into three of these tools. I will share a description of how they work first (or rather how I think they work), and will keep my observations and questions for the end. Note that these tools are very fast evolving, so they might have already changed since I used them in September.</p>
<h3>The Three Documents (and Why They’re Different)</h3>
<p>I see people conflating PRDs, design docs, and specs constantly. They serve different purposes.</p>
<p><strong>Product Requirements Document (PRD):</strong> For humans; product managers, stakeholders. Covers <em>what</em> we’re building and <em>why</em>. Business value, user stories, success metrics. This is a debate document.</p>
<p><strong>Technical Design Document:</strong> For engineers. Covers <em>how</em> we’re building it. Architecture decisions, scalability considerations, security implications. Also debated and reviewed.</p>
<p><strong>AI Spec:</strong> For agents. This is an <em>execution</em> document - not a debate, a plan. It translates decisions from the PRD and design doc into something an agent can act on.</p>
<p>In practice, you don’t always write all three. For a small feature, you might skip straight to a spec. For a large initiative, you’d have a PRD that spawns multiple design docs, each spawning multiple specs. The spec is always the final translation layer before code.</p>
<h3>Anatomy of a Good Spec</h3>
<p>A spec has four parts:</p>
<p><strong>1. Why (Brief Context)</strong></p>
<p>Keep this short. One or two sentences about the problem you’re solving. This helps the agent make intelligent decisions if it encounters ambiguity.</p>
<p><strong>2. What (Scope)</strong></p>
<p>Define the boundaries. What features are you building? Be specific about implementation details the agent would otherwise guess about.</p>
<p>Example: “JWT-based auth with one-hour access tokens and seven-day refresh tokens. Users can register, login, and refresh tokens.”</p>
<p><strong>3. Constraints (Boundaries)</strong></p>
<p>This is where you prevent the agent from being too eager. What libraries to use. What patterns to follow. What’s explicitly out of scope.</p>
<p>Example: “Use bcrypt for password hashing. Store user data in Postgres via Prisma. Must not add new dependencies. Must not store tokens in the database. Out of scope: password reset, OAuth, email verification.”</p>
<p><strong>4. Tasks (Discrete Work Units)</strong></p>
<p>Break the work into small, verifiable chunks. Each task should specify what to build, which files to touch, and how to verify completion.</p>
<p>Example:</p>
<ul>
<li><p>Task 1: Add user model to Prisma schema. Verify: npx prisma generate succeeds.</p>
</li>
<li><p>Task 2: Create registration endpoint. Verify: Test with curl, user appears in database.</p>
</li>
<li><p>Task 3: Create login endpoint. Verify: Returns valid JWT on correct credentials.</p>
</li>
</ul>
<h3>When Specs Go Wrong</h3>
<p>Specs fail in two directions.</p>
<p><strong>Over-specified:</strong> You’ve constrained the agent so tightly it can’t solve the problem. Signs: the agent keeps asking for permission, or produces convoluted code to satisfy contradictory constraints. Fix: loosen constraints, focus on outcomes rather than implementation details.</p>
<p><strong>Under-specified:</strong> The agent still has to guess. Signs: you review the code and find unexpected decisions - new files, different patterns, surprise dependencies. Fix: add the missing constraints. Each surprise is a constraint you forgot to write down.</p>
<p>The goal is a spec tight enough that the agent can’t make decisions you’d disagree with, but loose enough that it can solve problems you didn’t anticipate.</p>
<h3>My Workflow</h3>
<p>It’s important to point out that this level of planning isn’t always needed. If you’re fixing a simple bug, you likely don’t need extensive planning. Just do it. If you’re working on something large that might split into many tasks or run over multiple sessions - write a spec.</p>
<p>Here’s how I actually use specs day to day:</p>
<p><strong>Step 1: Generate.</strong> I describe what I want to build to the agent and ask it to write a spec—not implement the feature. I use a /spec command for this.</p>
<p><strong>Step 2: Iterate.</strong> I review the spec carefully. The agent will make assumptions. I correct them, add constraints I forgot, remove scope creep. This is where I catch problems before they become code.</p>
<p><strong>Step 3: Execute.</strong> I open a fresh session. I ask the agent to read the spec and implement Task 1. Review the code. Commit. Move to Task 2.</p>
<blockquote>
<p>“Read and implement T1”</p>
</blockquote>
<p><strong>Step 4: Adapt.</strong> Review the code. Could it be improved? Maybe Task 3 reveals a flaw in the spec. I go back and update it. This isn’t waterfall, it’s iterative. The spec is a living document.</p>
<p>The key insight: <strong>don’t ask the same agent to plan the work and do the work.</strong> Planning and execution are different modes. An agent that’s planning will think through edge cases. An agent that’s executing will rush to ship.</p>
<h3>Skip the Frameworks?</h3>
<p>There are a lot of spec-driven development frameworks out there. OpenSpec. Kiro. GitHub Spec Kit. I’ve tried them.</p>
<p>To me, they felt like overkill.</p>
<p>They generate tons of files. They want you to define user stories in markdown. They add ceremony that slows you down without adding value.</p>
<p>Here’s what you actually need: one slash command that acts as a meta-prompt to generate a spec.</p>
<p>&gt; “/spec implement rate limiting in the API.</p>
<p>The power of spec-driven development isn’t in the tooling. It’s in the practice of thinking before prompting. A fancy framework won’t fix sloppy thinking. A simple markdown file that forces you to articulate constraints is probably enough.</p>
<p>If you want a comparison of these tools, I recommend the excellent article <a href="https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html">Understanding Spec-Driven-Development: Kiro, spec-kit, and Tessl</a> by Birgitta Böckeler.</p>
<h3>Why This Creates Leverage</h3>
<p>Spec-driven development isn’t new. Software teams have always worked this way. PRD &gt; Design doc &gt; Task breakdown &gt; Implementation. The only difference is we’re handing tasks to agents instead of other developers.</p>
<p>But here’s what changes: an agent that executes well-defined specs can move faster than any human. The bottleneck shifts from implementation to specification. Your job becomes defining work clearly enough that an agent can execute it autonomously.</p>
<p><a href="https://newsletter.owainlewis.com/p/how-i-code-with-ai-agents-spec-driven">https://newsletter.owainlewis.com/p/how-i-code-with-ai-agents-spec-driven</a></p>
<p><a href="https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html">https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html</a></p>
<p><a href="https://heeki.medium.com/using-spec-driven-development-with-claude-code-4a1ebe5d9f29">https://heeki.medium.com/using-spec-driven-development-with-claude-code-4a1ebe5d9f29</a></p>
<p><a href="https://marmelab.com/blog/2025/11/12/spec-driven-development-waterfall-strikes-back.html?ref=dailydev">https://marmelab.com/blog/2025/11/12/spec-driven-development-waterfall-strikes-back.html?ref=dailydev</a></p>
<p><a href="https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/">https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/</a></p>
<h2><strong>Claude Code Ralph Loop</strong></h2>
<p>Every Claude Code session has the same hidden flaw; <em><strong>Claude stops when it thinks the job is done.</strong></em></p>
<ul>
<li><p>Tests broken</p>
</li>
<li><p>API half-implemented,</p>
</li>
<li><p>Edge cases untouched</p>
</li>
</ul>
<p>But it declares complete and exits. And the longer and more complex the task, the worse it gets.</p>
<blockquote>
<p><em><strong>There is a technique designed to fix this problem. You have probably heard the word “Ralph” thrown around.</strong></em></p>
</blockquote>
<p>It’s a simple idea that forces Claude to keep iterating until the work is genuinely completed.</p>
<p>Surprisingly, this technique has been used to ship entire projects overnight at a fraction of the actual cost.</p>
<blockquote>
<p><em><strong>In this newsletter, I’ll take you from understanding why Claude fails on complex tasks to building the full Ralph Loop system and running it on real projects.</strong></em></p>
</blockquote>
<p>We’ll cover the Ralph core mechanism, the PRD and memory architecture, and everything you need to put Ralph Loop to work.</p>
<p>Let’s start with the basics.</p>
<h3><strong>What is Ralph Loop?</strong></h3>
<p>Let me start with something that might surprise you.</p>
<blockquote>
<p><em><strong>Ralph Loop isn’t a framework, and it is not a sophisticated AI orchestration system. At the core, it’s a Bash while loop.</strong></em></p>
</blockquote>
<pre><code class="language-plaintext">while true; do
  cat prompt.md | claude
done
</code></pre>
<p>The technique was created by <a href="https://github.com/ghuntley">Jeffrey Huntley</a></p>
<p><em><strong>The name comes from</strong></em> <a href="https://en.wikipedia.org/wiki/Ralph_Wiggum"><em><strong>Ralph Wiggum</strong></em></a><em><strong>, arguably the dumbest character in</strong></em> <a href="https://en.wikipedia.org/wiki/The_Simpsons"><em><strong>The Simpsons</strong></em></a><em><strong>. Ralph fails constantly, making silly mistakes. But stubbornly continues in an endless loop until he eventually succeeds.</strong></em></p>
<p>This childlike persistence is the philosophy behind the technique.</p>
<blockquote>
<p><em><strong>With Ralph Loop, Claude is no longer allowed to exit when it thinks it’s done. It’s forced to keep working until the task is truly finished.</strong></em></p>
</blockquote>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/786cf4cd-3cbe-4111-93e2-0a11f3b080f7.webp" alt="" style="display:block;margin:0 auto" />

<p>The key insight is that Ralph Loop treats failure as expected, not exceptional.</p>
<p><em><strong>Each iteration builds on the last. The AI sees what it did before, recognizes what’s still broken, and improves.</strong></em></p>
<hr />
<h3><strong>Why Claude Code Needs Ralph</strong></h3>
<p>Claude Code has a limitation that most developers don’t recognize until they’ve hit it repeatedly.</p>
<p><em>It operates in single-pass mode.</em></p>
<p>Even though Claude reasons extremely well, it stops as soon as it believes the output is “good enough.”</p>
<blockquote>
<p><em><strong>The model has what you might call an implicit execution budget. Once it feels like it’s done reasonable work, it wraps up and exits.</strong></em></p>
</blockquote>
<p>The problem is that “ good enough”, according to Claude, often isn’t good enough.</p>
<p>I’ve seen this pattern dozens of times:</p>
<ul>
<li><p><em>C</em><em><strong>laude builds a feature, declares it complete, but the edge cases are broken</strong></em></p>
</li>
<li><p><em><strong>Claude writes tests, says they pass, but they don’t actually run</strong></em></p>
</li>
<li><p><em><strong>Claude implements an API, marks it done, but forgot error handling</strong></em></p>
</li>
</ul>
<p>It believes it’s finished, but it’s making that judgment based on what the code looks like, not whether it works.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/1f373e3c-f351-43e8-9fce-8bee831e1d6d.webp" alt="" style="display:block;margin:0 auto" />

<blockquote>
<p><em><strong>Another problem that makes this worse is the context rot.</strong></em></p>
</blockquote>
<p>As the conversation with Claude gets longer, the context window fills up. The model’s reasoning quality degrades as it has to juggle more information.</p>
<p><em><strong>Jeffrey Huntley calls this “compaction” — when the context gets summarized and loses important details. The model starts forgetting things it knew earlier in the conversation. It makes mistakes it wouldn’t have made with a fresh context.</strong></em></p>
<p>This is why the single-pass approach fails for complex tasks.</p>
<p>By the time Claude reaches the end of a big feature, its context is bloated with attempts, errors, and fixes. The quality of its reasoning has degraded.</p>
<p>Ralph Loop solves both problems:</p>
<ol>
<li><p><em><strong>Forces verification</strong></em> <em>— Claude can’t exit until it proves the work is done</em></p>
</li>
<li><p><em><strong>Fresh context</strong></em> <em>— Each iteration starts clean, avoiding context</em> rot</p>
</li>
</ol>
<p><a href="https://newsletter.claudecodemasterclass.com/p/claude-code-ralph-loop-from-basic?utm_source=post-email-title&amp;publication_id=5791503&amp;post_id=186188688&amp;utm_campaign=email-post-title&amp;isFreemail=true&amp;r=2d5wj&amp;triedRedirect=true&amp;utm_medium=email">https://newsletter.claudecodemasterclass.com/p/claude-code-ralph-loop-from-basic</a></p>
<h2>Conductors to Orchestrators: The Future of Agentic Coding</h2>
<p><strong>AI coding assistants</strong> have quickly moved from novelty to necessity where up to 90% of software engineers use some kind of AI for coding. But a new paradigm is emerging in software development - one where engineers leverage <strong>fleets of autonomous coding agents</strong>. In this agentic future, the role of the software engineer is evolving from <strong>implementer</strong> to <strong>manager</strong>, or in other words, from <em>coder</em> to <strong>conductor</strong> and ultimately <a href="https://www.youtube.com/watch?v=sQFIiB6xtIs"><strong>orchestrator</strong></a>.</p>
<p>Over time, developers will increasingly <strong>guide AI agents to build the right code</strong> and coordinate multiple agents working in concert. This write-up explores the distinction between <strong>Conductors</strong> and <strong>Orchestrators</strong> in AI-assisted coding, defines these roles, and examines how today’s cutting-edge tools embody each approach. Senior engineers may start to see the writing on the wall: our jobs are shifting from <em>“How do I code this?”</em> to <em>“How do I get the right code built?”</em> - a subtle but profound change.</p>
<p>What’s the tl;dr of an orchestrator tool? It supports multi-agent workflows where you can run many agents in parallel without them interfering with each another. But let’s talk terminology more first.</p>
<p><a href="https://addyo.substack.com/p/conductors-to-orchestrators-the-future">https://addyo.substack.com/p/conductors-to-orchestrators-the-future</a></p>
<h2>Critical Thinking during the age of AI</h2>
<p>In a time where AI can generate code, design ideas, and occasionally plausible answers on demand, the need for <strong>human critical thinking</strong> is greater than ever. Even the smartest automation can’t replace the ability to ask the right questions, challenge assumptions, and think independently at this time.</p>
<p>This essay explores the importance of critical thinking skills for software engineers and technical teams using the classic <strong>“Who, what, where, when, why, how”</strong> framework to structure pragmatic guidance.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/2b9ef6a3-04b7-45ce-b9fb-6b36d936799a.webp" alt="" style="display:block;margin:0 auto" />

<p><strong>Critical thinking checklist for AI-augmented teams</strong></p>
<ul>
<li><p><strong>Who:</strong> Don’t rely on AI as an oracle. Verify its output.</p>
</li>
<li><p><strong>What:</strong> Define the <em>real</em> problem before rushing to a solution.</p>
</li>
<li><p><strong>Where:</strong> Context is king. A fix that works in a sandbox might break in production.</p>
</li>
<li><p><strong>When:</strong> Know when to use a quick heuristic (triage) vs. deep analysis (root cause).</p>
</li>
<li><p><strong>Why:</strong> Use the “5 Whys” technique to uncover underlying causes.</p>
</li>
<li><p><strong>How:</strong> Communicate with evidence and data, not just opinions.</p>
</li>
</ul>
<p>We’ll dive into how each of these question categories applies to decision-making in an AI-augmented world, with concrete examples and common pitfalls. The goal is to show how humble curiosity and evidence-based reasoning can keep projects on track and avoid downstream issues.</p>
<p><a href="https://addyo.substack.com/p/critical-thinking-during-the-age">https://addyo.substack.com/p/critical-thinking-during-the-age</a></p>
<h2><strong>Harness Engineering</strong></h2>
<h3>Why AI Agents Fail on Large Files</h3>
<p>Most engineers today interact with AI coding tools the same way: open Cursor, Claude Code, or Codex, type a prompt, review the output, repeat. For small files and isolated tasks, this works beautifully. But the moment the problem involves a large amount of files, the whole approach falls apart.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/bb1ef92b-ad0b-43c5-99dd-b5fa0901026f.webp" alt="" style="display:block;margin:0 auto" />

<p>Large Language Models are probabilistic engines. They predict the next token based on patterns in their context window. When the context window is filled with thousands of lines of structured data, the model’s attention gets diluted. It correctly identifies the node you want to modify, but it loses track of sibling keys, nested brackets, and structural integrity. The result is a file that looks right at the point of change but is broken somewhere else.</p>
<p>We have to understand that <strong>Context Window</strong> isn’t the same as <strong>Context Attention.</strong> As a human, I can store hundreds of items in a storage unit, but I will remember about a fraction of the items I have there.</p>
<p>Same with LLMs. Performance degrades as the context window gets filled (and costs).</p>
<blockquote>
<p><strong>Did you know that every message you send is sending all the previous conversation in an API call?</strong> Yes, you’re billed also for those past messages. The servers in the cloud don’t keep any state, they only have a cache.</p>
</blockquote>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/0cf3af3f-cd84-471f-a1e0-64c1821f4dca.webp" alt="" style="display:block;margin:0 auto" />

<p>When the model fails to make an update, the instinct is to write a better prompt.</p>
<p>Add more constraints.</p>
<p>Tell the model to “preserve the surrounding structure.”</p>
<p>“Make no mistakes.”</p>
<p>But that is like asking someone to juggle while blindfolded and then giving them more detailed instructions about hand positioning. The problem is not the instructions. The problem is the blindfold.</p>
<p>The context window itself becomes a liability when it’s packed with thousands of lines of repetitive structure. No prompt can fix that.</p>
<p>I covered in this post how to scale AI, setting up guardrails</p>
<h3>What Is Harness Engineering?</h3>
<p><strong>Harness engineering is the discipline of designing the systems, architectural constraints, execution environments, and automated feedback loops that wrap around AI agents to make them reliable in production.</strong></p>
<p>The term was first coined by Mitchell Hashimoto, the founder of HashiCorp. The metaphor comes from horse riding. Think of the LLM as a powerful horse. It has raw energy, speed, and strength. But without reins, a saddle, and a bridle, that energy is undirected and potentially destructive (the horse kicks you, the LLM runs a <code>rm -rf</code>, and I don’t know which is worse<code>)</code>. The harness allows the rider to direct the horse’s power productively.</p>
<p>To understand where harness engineering fits, here’s how it relates to the other disciplines you’ve probably heard about:</p>
<ul>
<li><p><strong>Prompt Engineering</strong> → Single interaction to craft the best input to the model (single request-response interaction).</p>
</li>
<li><p><strong>Context Engineering</strong> → Control what the model sees during a whole session (multiple interactions until clearing).</p>
</li>
<li><p><strong>Harness Engineering</strong> → Designs the environment, tools, guardrails, and feedback loops (multiple sessions).</p>
</li>
<li><p><strong>Agent Engineering</strong> → Design the agent’s internal reasoning loop (define specialized agents).</p>
</li>
<li><p><strong>Platform Engineering</strong> → Infrastructure to manage deployment, scaling, and cloud operations (where agents can run).</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/45419dc8-72f7-456f-9462-6d9587f765de.webp" alt="" style="display:block;margin:0 auto" />

<p>Prompt engineering is about what you say to the model.</p>
<p>Context engineering is about what the model sees.</p>
<p>Harness engineering is about the entire world the model operates in. It includes the tools the agent can call, the constraints it cannot violate, the documentation structure it reads, and the automated feedback loops that catch its mistakes before they reach production.</p>
<p><a href="https://strategizeyourcareer.com/p/harness-engineering-ai-agents">https://strategizeyourcareer.com/p/harness-engineering-ai-agents</a></p>
<h1>AI Best Practices</h1>
<h2>LLM Coding Workflow</h2>
<p><a href="https://addyo.substack.com/p/my-llm-coding-workflow-going-into">https://addyo.substack.com/p/my-llm-coding-workflow-going-into</a></p>
<p><a href="https://newsletter.systemdesign.one/p/ai-coding-workflow?ref=dailydev">https://newsletter.systemdesign.one/p/ai-coding-workflow?ref=dailydev</a></p>
<p><a href="https://escobyte.substack.com/p/writing-high-quality-production-code">https://escobyte.substack.com/p/writing-high-quality-production-code</a></p>
<p><strong>AI coding assistants became game-changers this year, but harnessing them effectively takes skill and structure.</strong> These tools dramatically increased what LLMs can do for real-world coding, and many developers (myself included) embraced them.</p>
<p>At Anthropic, for example, engineers adopted Claude Code so heavily that <a href="https://newsletter.pragmaticengineer.com/p/software-engineering-with-llms-in-2025#:~:text=,%E2%80%9D">today</a> <strong>~90% of the code for Claude Code is written by Claude Code itself</strong>. Yet, using LLMs for programming is <em>not</em> a push-button magic experience - it’s “difficult and unintuitive” and getting great results requires learning new patterns. <a href="https://addyo.substack.com/p/critical-thinking-during-the-age">Critical thinking</a> remains key. Over a year of projects, I’ve converged on a workflow similar to what many experienced devs are discovering: treat the LLM as a powerful pair programmer that <strong>requires clear direction, context and oversight</strong> rather than autonomous judgment.</p>
<h3><strong>Start with a clear plan (specs before code)</strong></h3>
<p><a href="https://addyo.substack.com/p/how-to-write-a-good-spec-for-ai-agents">https://addyo.substack.com/p/how-to-write-a-good-spec-for-ai-agents</a></p>
<p><strong>Don’t just throw wishes at the LLM - begin by defining the problem and planning a solution.</strong></p>
<p>One common mistake is diving straight into code generation with a vague prompt. In my workflow, and in many others’, the first step is <strong>brainstorming a detailed specification</strong> <em>with</em> the AI, then outlining a step-by-step plan, <em>before</em> writing any actual code. For a new project, I’ll describe the idea and ask the LLM to <strong>iteratively ask me questions</strong> until we’ve fleshed out requirements and edge cases. By the end, we compile this into a comprehensive <strong>spec.md</strong> - containing requirements, architecture decisions, data models, and even a testing strategy. This spec forms the foundation for development.</p>
<p>Next, I feed the spec into a reasoning-capable model and prompt it to <strong>generate a project plan</strong>: break the implementation into logical, bite-sized tasks or milestones. The AI essentially helps me do a mini “design doc” or project plan. I often iterate on this plan - editing and asking the AI to critique or refine it - until it’s coherent and complete. <em>Only then</em> do I proceed to coding. This upfront investment might feel slow, but it pays off enormously. As Les Orchard <a href="https://blog.lmorchard.com/2025/06/07/semi-automatic-coding/#:~:text=Accidental%20waterfall%20">put it</a>, it’s like doing a <strong>“waterfall in 15 minutes”</strong> - a rapid structured planning phase that makes the subsequent coding much smoother.v</p>
<p>Having a clear spec and plan means when we unleash the codegen, both the human and the LLM know exactly what we’re building and why. In short, <strong>planning first</strong> forces you and the AI onto the same page and prevents wasted cycles. It’s a step many people are tempted to skip, but experienced LLM developers now treat a robust spec/plan as the cornerstone of the workflow.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/8f069d25-8fc3-4b86-b9dd-48bccfbb8de3.webp" alt="" style="display:block;margin:0 auto" />

<p><strong>Scope management is everything - feed the LLM manageable tasks, not the whole codebase at once.</strong></p>
<p>A crucial lesson I’ve learned is to avoid asking the AI for large, monolithic outputs. Instead, we <strong>break the project into iterative steps or tickets</strong> and tackle them <a href="https://blog.fsck.com/2025/10/05/how-im-using-coding-agents-in-september-2025/#:~:text=please%20write%20out%20this%20plan%2C,in%20full%20detail%2C%20into%20docs%2Fplans">one by one</a>. LLMs do best when given focused prompts: implement one function, fix one bug, add one feature at a time. For example, after planning, I will prompt the codegen model: <em>“Okay, let’s implement Step 1 from the plan”</em>. We code that, test it, then move to Step 2, and so on. Each chunk is small enough that the AI can handle it within context and you can understand the code it produces.</p>
<p>This approach guards against the model going off the rails. If you ask for too much in one go, it’s likely to get confused or produce a <strong>“jumbled mess”</strong> that’s hard to untangle. Developers <a href="https://albertofortin.com/writing/coding-with-ai#:~:text=No%20consistency%2C%20no%20overarching%20plan,the%20other%209%20were%20doing">report</a> that when they tried to have an LLM generate huge swaths of an app, they ended up with inconsistency and duplication - “like 10 devs worked on it without talking to each other,” one said. I’ve felt that pain; the fix is to <strong>stop, back up, and split the problem into smaller pieces</strong>. Each iteration, we carry forward the context of what’s been built and incrementally add to it. This also fits nicely with a <strong>test-driven development (TDD)</strong> approach - we can write or generate tests for each piece as we go (more on testing soon).</p>
<p>Several coding-agent tools now explicitly support this chunked workflow. For instance, I often generate a structured <strong>“prompt plan”</strong> file that contains a sequence of prompts for each task, so that tools like Cursor can execute them one by one. The key point is to <strong>avoid huge leaps</strong>. By iterating in small loops, we greatly reduce the chance of catastrophic errors and we can course-correct quickly. LLMs excel at quick, contained tasks - use that to your advantage.</p>
<h3><strong>Provide extensive context and guidance</strong></h3>
<p><strong>LLMs are only as good as the context you provide - <em>show them</em> the relevant code, docs, and constraints.</strong></p>
<p>When working on a codebase, I make sure to <strong>feed the AI all the information it needs</strong> to perform well. That includes the code it should modify or refer to, the project’s technical constraints, and any known pitfalls or preferred approaches. Modern tools help with this: for example, Anthropic’s Claude can import an entire GitHub repo into its context in “Projects” mode, and IDE assistants like Cursor or Copilot auto-include open files in the prompt. But I often go further - I will either use an MCP like <a href="https://context7.com/">Context7</a> or manually copy important pieces of the codebase or API docs into the conversation if I suspect the model doesn’t have them.</p>
<p>Expert LLM users emphasize this “context packing” step. For example, doing a <strong>“brain dump”</strong> of everything the model should know before coding, including: high-level goals and invariants, examples of good solutions, and warnings about approaches to avoid. If I’m asking an AI to implement a tricky solution, I might tell it which naive solutions are too slow, or provide a reference implementation from elsewhere. If I’m using a niche library or a brand-new API, I’ll paste in the official docs or README so the AI isn’t flying blind. All of this upfront context dramatically improves the quality of its output, because the model isn’t guessing - it has the facts and constraints in front of it.</p>
<p>There are now utilities to automate context packaging. I’ve experimented with tools like <a href="https://gitingest.com/"><strong>gitingest</strong></a> or <a href="https://github.com/abinthomasonline/repo2txt"><strong>repo2txt</strong></a>, which essentially <strong>“dump” the relevant parts of your codebase into a text file for the LLM to read</strong>. These can be a lifesaver when dealing with a large project - you generate an output.txt bundle of key source files and let the model ingest that. The principle is: <strong>don’t make the AI operate on partial information</strong>. If a bug fix requires understanding four different modules, show it those four modules. Yes, we must watch token limits, but current frontier models have pretty huge context windows (tens of thousands of tokens). Use them wisely. I often selectively include just the portions of code relevant to the task at hand, and explicitly tell the AI what <em>not</em> to focus on if something is out of scope (to save tokens).</p>
<p>I think Claude Skills have potential because they turn what used to be fragile repeated prompting into something <strong>durable and reusable</strong> by packaging instructions, scripts, and domain-specific expertise into modular capabilities that tools can automatically apply when a request matches the Skill. This means you get more reliable and context aware results than a generic prompt ever could and you move away from one off interactions toward workflows that encode repeatable procedures and team knowledge for tasks in a consistent way. A number of community-curated <a href="https://www.x-cmd.com/skill/">Skill Collections</a> exist, but one of my favorite examples is the but one of my favorite examples is the <a href="https://x.com/trq212/status/1989061937590837678">frontend-design</a> skill which can “end” the purple design aesthetic prevalent in LLM generated UIs. Until more tools support Skills officially, <a href="https://github.com/intellectronica/skillz">workarounds</a> exist.</p>
<p>Finally, <strong>guide the AI with comments and rules inside the prompt</strong>. I might precede a code snippet with: “Here is the current implementation of X. We need to extend it to do Y, but be careful not to break Z.” These little hints go a long way. LLMs are <strong>literalists</strong> - they’ll follow instructions, so give them detailed, contextual instructions. By proactively providing context and guidance, we minimize hallucinations and off-base suggestions and get code that fits our project’s needs.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/b6dbee1a-e2dc-4da4-b53f-0622584e4469.webp" alt="" style="display:block;margin:0 auto" />

<h3><strong>Choose the right model (and use multiple when needed)</strong></h3>
<p><strong>Not all coding LLMs are equal - pick your tool with intention, and don’t be afraid to swap models mid-stream.</strong></p>
<p>In 2025 we’ve been spoiled with a variety of capable code-focused LLMs. Part of my workflow is <strong>choosing the model or service best suited to each task</strong>. Sometimes it can be valuable to even try two or more LLMs in parallel to cross-check how they might approach the same problem differently.</p>
<p>Each model has its own “personality”. The key is: <strong>if one model gets stuck or gives mediocre outputs, try another.</strong> I’ve literally copied the same prompt from one chat into another service to see if it can handle it better. This “<a href="https://blog.lmorchard.com/2025/06/07/semi-automatic-coding/#:~:text=I%20bounced%20between%20Claude%20Sonnet,Each%20had%20its%20own%20personality">model musical chairs</a>” can rescue you when you hit a model’s blind spot.</p>
<p>Also, make sure you’re using <em>the best version</em> available. If you can, use the newest “pro” tier models - because quality matters. And yes, it often means paying for access, but the productivity gains can justify it. Ultimately, pick the AI pair programmer whose <strong>“vibe” meshes with you</strong>. I know folks who prefer one model simply because they like how its responses <em>feel</em>. That’s valid - when you’re essentially in a constant dialogue with an AI, the UX and tone make a difference.</p>
<p>Personally I gravitate towards Gemini for a lot of coding work these days because the interaction feels more natural and it often understands my requests on the first try. But I will not hesitate to switch to another model if needed; sometimes a second opinion helps the solution emerge. In summary: <strong>use the best tool for the job, and remember you have an arsenal of AIs at your disposal.</strong></p>
<h3><strong>Leverage AI coding across the lifecycle</strong></h3>
<p><strong>Supercharge your workflow with coding-specific AI help across the SDLC.</strong></p>
<p>On the command-line, new AI agents emerged. <strong>Claude Code, OpenAI’s Codex CLI</strong> and <strong>Google’s Gemini CLI</strong> are CLI tools where you can chat with them directly in your project directory - they can read files, run tests, and even multi-step fix issues. I’ve used Google’s <strong>Jules</strong> and GitHub’s <strong>Copilot Agent</strong> as well - these are <strong>asynchronous coding agents</strong> that actually clone your repo into a cloud VM and work on tasks in the background (writing tests, fixing bugs, then opening a PR for you). It’s a bit eerie to witness: you issue a command like “refactor the payment module for X” and a little while later you get a pull request with code changes and passing tests. We are truly living in the future. You can read more about this in <a href="https://addyo.substack.com/p/conductors-to-orchestrators-the-future">conductors to orchestrators</a>.</p>
<p>That said, <strong>these tools are not infallible, and you must understand their limits</strong>. They accelerate the mechanical parts of coding - generating boilerplate, applying repetitive changes, running tests automatically - but they still benefit greatly from your guidance. For instance, when I use an agent like Claude or Copilot to implement something, I often supply it with the plan or to-do list from earlier steps so it knows the exact sequence of tasks. If the agent supports it, I’ll load up my spec.md or plan.md in the context before telling it to execute. This keeps it on track.</p>
<p><strong>We’re not at the stage of letting an AI agent code an entire feature unattended</strong> and expecting perfect results. Instead, I use these tools in a supervised way: I’ll let them generate and even run code, but I keep an eye on each step, ready to step in when something looks off. There are also orchestration tools like <strong>Conductor</strong> that let you run multiple agents in parallel on different tasks (essentially a way to scale up AI help) - some engineers are experimenting with running 3-4 agents at once on separate features. I’ve dabbled in this “massively parallel” approach; it’s surprisingly effective at getting a lot done quickly, but it’s also mentally taxing to monitor multiple AI threads! For most cases, I stick to one main agent at a time and maybe a secondary one for reviews (discussed below).</p>
<p>Just remember these are power tools - you still control the trigger and guide the outcome.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/df334fce-b8d1-47c1-beba-f662561e262e.webp" alt="" style="display:block;margin:0 auto" />

<h3><strong>Keep a human in the loop - verify, test, and review everything</strong></h3>
<p><strong>AI will happily produce plausible-looking code, but <em>you</em> are responsible for quality - always review and test thoroughly.</strong> One of my cardinal rules is never to blindly trust an LLM’s output. As Simon Willison aptly <a href="https://simonwillison.net/2025/Mar/11/using-llms-for-code/#:~:text=Instead%2C%20use%20them%20to%20augment,on%20tedious%20tasks%20without%20complaint">says</a>, think of an LLM pair programmer as <strong>“over-confident and prone to mistakes”</strong>. It writes code with complete conviction - including bugs or nonsense - and won’t tell you something is wrong unless you catch it. So I treat every AI-generated snippet as if it came from a junior developer: I read through the code, run it, and test it as needed. <strong>You absolutely have to test what it writes</strong> - run those unit tests, or manually exercise the feature, to ensure it does what it claims. Read more about this in <a href="https://addyo.substack.com/p/vibe-coding-is-not-an-excuse-for">vibe coding is not an excuse for low-quality work</a>.</p>
<p>In fact, I weave testing into the workflow itself. My earlier planning stage often includes generating a list of tests or a testing plan for each step. If I’m using a tool like Claude Code, I’ll instruct it to run the test suite after implementing a task, and have it debug failures if any occur. This kind of tight feedback loop (write code → run tests → fix) is something AI excels at <em>as long as the tests exist</em>. It’s no surprise that those who get the most out of coding agents tend to be those with strong testing practices. An agent like Claude can “fly” through a project with a good test suite as safety net. Without tests, the agent might blithely assume everything is fine (“sure, all good!”) when in reality it’s broken several things. So, <strong>invest in tests</strong> - it amplifies the AI’s usefulness and confidence in the result.</p>
<p>Even beyond automated tests, <strong>do code reviews - both manual and AI-assisted</strong>. I routinely pause and review the code that’s been generated so far, line by line. Sometimes I’ll spawn a second AI session (or a different model) and ask <em>it</em> to critique or review code produced by the first. For example, I might have Claude write the code and then ask Gemini, “Can you review this function for any errors or improvements?” This can catch subtle issues. The key is to <em>not</em> skip the review just because an AI wrote the code. If anything, AI-written code needs <strong>extra scrutiny</strong>, because it can sometimes be superficially convincing while hiding flaws that a human might not immediately notice.</p>
<p>I also use <a href="https://github.com/chromeDevTools/chrome-devtools-mcp/">Chrome DevTools MCP</a>, built with my last team, for my <strong>debugging and quality loop</strong> to bridge the gap between static code analysis and live browser execution. It “gives your agent eyes”. It lets me grant my AI tools direct access to see what the browser can, inspect the DOM, get rich performance traces, console logs or network traces. This integration eliminates the friction of manual context switching, allowing for automated UI testing directly through the LLM. It means bugs can be diagnosed and fixed with high precision based on actual runtime data.</p>
<p>The dire consequences of skipping human oversight have been documented. One developer who leaned heavily on AI generation for a rush project <a href="https://albertofortin.com/writing/coding-with-ai#:~:text=No%20consistency%2C%20no%20overarching%20plan,the%20other%209%20were%20doing">described</a> the result as an inconsistent mess - duplicate logic, mismatched method names, no coherent architecture. He realized he’d been “building, building, building” without stepping back to really see what the AI had woven together. The fix was a painful refactor and a vow to never let things get that far out of hand again. I’ve taken that to heart. <strong>No matter how much AI I use, I remain the accountable engineer</strong>.</p>
<p>In practical terms, that means I only merge or ship code after I’ve understood it. If the AI generates something convoluted, I’ll ask it to add comments explaining it, or I’ll rewrite it in simpler terms. If something doesn’t feel right, I dig in - just as I would if a human colleague contributed code that raised red flags.</p>
<p>It’s all about mindset: <strong>the LLM is an assistant, not an autonomously reliable coder</strong>. I am the senior dev; the LLM is there to accelerate me, not replace my judgment. Maintaining this stance not only results in better code, it also protects your own growth as a developer. (I’ve heard some express concern that relying too much on AI might dull their skills - I think as long as you stay in the loop, actively reviewing and understanding everything, you’re still sharpening your instincts, just at a higher velocity.) In short: <strong>stay alert, test often, review always.</strong> It’s still your codebase at the end of the day.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/ad69ffdc-b7b8-4d17-8152-270894cef07f.webp" alt="" style="display:block;margin:0 auto" />

<h3><strong>Commit often and use version control as a safety net. Never commit code you can’t explain.</strong></h3>
<p><strong>Frequent commits are your save points - they let you undo AI missteps and understand changes.</strong></p>
<p>When working with an AI that can generate a lot of code quickly, it’s easy for things to veer off course. I mitigate this by adopting ultra-granular version control habits. I commit early and often, even more than I would in normal hand-coding. After each small task or each successful automated edit, I’ll make a git commit with a clear message. This way, if the AI’s next suggestion introduces a bug or a messy change, I have a recent checkpoint to revert to (or cherry-pick from) without losing hours of work. One practitioner likened it to treating commits as <strong>“save points in a game”</strong> - if an LLM session goes sideways, you can always roll back to the last stable commit. I’ve found that advice incredibly useful. It’s much less stressful to experiment with a bold AI refactor when you know you can undo it with a git reset if needed.</p>
<p>Proper version control also helps when collaborating with the AI. Since I can’t rely on the AI to remember everything it’s done (context window limitations, etc.), the git history becomes a valuable log. I often scan my recent commits to brief the AI (or myself) on what changed. In fact, LLMs themselves can leverage your commit history if you provide it - I’ve pasted git diffs or commit logs into the prompt so the AI knows what code is new or what the previous state was. Amusingly, LLMs are <em>really</em> good at parsing diffs and using tools like git bisect to find where a bug was introduced. They have infinite patience to traverse commit histories, which can augment your debugging. But this only works if you have a tidy commit history to begin with.</p>
<p>Another benefit: small commits with good messages essentially document the development process, which helps when doing code review (AI or human). If an AI agent made five changes in one go and something broke, having those changes in separate commits makes it easier to pinpoint which commit caused the issue. If everything is in one giant commit titled “AI changes”, good luck! So I discipline myself: <em>finish task, run tests, commit.</em> This also meshes well with the earlier tip about breaking work into small chunks - each chunk ends up as its own commit or PR.</p>
<p>Finally, don’t be afraid to <strong>use branches or worktrees</strong> to isolate AI experiments. One advanced workflow I’ve adopted (inspired by folks like Jesse Vincent) is to spin up a fresh git worktree for a new feature or sub-project. This lets me run multiple AI coding sessions in parallel on the same repo without them interfering, and I can later merge the changes. It’s a bit like having each AI task in its own sandbox branch. If one experiment fails, I throw away that worktree and nothing is lost in main. If it succeeds, I merge it in. This approach has been crucial when I’m, say, letting an AI implement Feature A while I (or another AI) work on Feature B simultaneously. Version control is what makes this coordination possible. In short: <strong>commit often, organize your work with branches, and embrace git</strong> as the control mechanism to keep AI-generated changes manageable and reversible.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5fdebe1f1485f22e24b356b6/04af8d0b-7da6-4cef-87cf-7ad6a200ba64.webp" alt="" style="display:block;margin:0 auto" />

<h3><strong>Customize the AI’s behavior with rules and examples</strong></h3>
<p><strong>Steer your AI assistant by providing style guides, examples, and even “rules files” - a little upfront tuning yields much better outputs.</strong></p>
<p>One thing I learned is that you don’t have to accept the AI’s default style or approach - you can influence it heavily by giving it guidelines. For instance, I have a <a href="http://CLAUDE.md"><strong>CLAUDE.md</strong></a> file that I update periodically, which contains process rules and preferences for Claude (Anthropic’s model) to follow (and similarly a <a href="http://GEMINI.md">GEMINI.md</a> when using Gemini CLI). This includes things like “write code in our project’s style, follow our lint rules, don’t use certain functions, prefer functional style over OOP,” etc. When I start a session, I feed this file to Claude to align it with our conventions. It’s surprising how well this works to keep the model “on track” as Jesse Vincent <a href="https://blog.fsck.com/2025/10/05/how-im-using-coding-agents-in-september-2025/#:~:text=I%27m%20still%20primarily%20using%20Claude,Code">noted</a> - it reduces the tendency of the AI to go off-script or introduce patterns we don’t want.</p>
<p>Even without a fancy rules file, you can <strong>set the tone with custom instructions or system prompts</strong>. GitHub Copilot and Cursor both introduced features to let you configure the AI’s behavior <a href="https://benjamincongdon.me/blog/2025/02/02/How-I-Use-AI-Early-2025/#:~:text=stuck,my%20company%E2%80%99s%20%2F%20team%E2%80%99s%20codebase">globally</a> for your project. I’ve taken advantage of that by writing a short paragraph about our coding style, e.g. “Use 4 spaces indent, avoid arrow functions in React, prefer descriptive variable names, code should pass ESLint.” With those instructions in place, the AI’s suggestions adhere much more closely to what a human teammate might write. Ben Congdon <a href="https://benjamincongdon.me/blog/2025/02/02/How-I-Use-AI-Early-2025/#:~:text=roughly%20on%20par,get%20past%20a%20logical%20impasse">mentioned</a> how shocked he was that few people use <strong>Copilot’s custom instructions</strong>, given how effective they are - he could guide the AI to output code matching his team’s idioms by providing some examples and preferences upfront. I echo that: take the time to teach the AI your expectations.</p>
<p>Another powerful technique is providing <strong>in-line examples</strong> of the output format or approach you want. If I want the AI to write a function in a very specific way, I might first show it a similar function already in the codebase: “Here’s how we implemented X, use a similar approach for Y.” If I want a certain commenting style, I might write a comment myself and ask the AI to continue in that style. Essentially, <em>prime</em> the model with the pattern to follow. LLMs are great at mimicry - show them one or two examples and they’ll continue in that vein.</p>
<p>The community has also come up with creative “rulesets” to tame LLM behavior. You might have heard of the <a href="https://harper.blog/2025/04/17/an-llm-codegen-heros-journey/#:~:text=repository,it%20in%20a%20few%20steps">“Big Daddy” rule</a> or adding a “no hallucination/no deception” clause to prompts. These are basically tricks to remind the AI to be truthful and not overly fabricate code that doesn’t exist. For example, I sometimes prepend a prompt with: “If you are unsure about something or the codebase context is missing, ask for clarification rather than making up an answer.” This reduces hallucinations. Another rule I use is: “Always explain your reasoning briefly in comments when fixing a bug.” This way, when the AI generates a fix, it will also leave a comment like “// Fixed: Changed X to Y to prevent Z (as per spec).” That’s super useful for later review.</p>
<p>In summary, <strong>don’t treat the AI as a black box - tune it</strong>. By configuring system instructions, sharing project docs, or writing down explicit rules, you turn the AI into a more specialized developer on your team. It’s akin to onboarding a new hire: you’d give them the style guide and some starter tips, right? Do the same for your AI pair programmer. The return on investment is huge: you get outputs that need less tweaking and integrate more smoothly with your codebase.</p>
<h3><strong>Embrace testing and automation as force multipliers</strong></h3>
<p><strong>Use your CI/CD, linters, and code review bots - AI will work best in an environment that catches mistakes automatically.</strong></p>
<p>This is a corollary to staying in the loop and providing context: a well-oiled development pipeline enhances AI productivity. I ensure that any repository where I use heavy AI coding has a robust <strong>continuous integration setup</strong>. That means automated tests run on every commit or PR, code style checks (like ESLint, Prettier, etc.) are enforced, and ideally a staging deployment is available for any new branch. Why? Because I can let the AI trigger these and evaluate the results. For instance, if the AI opens a pull request via a tool like Jules or GitHub Copilot Agent, our CI will run tests and report failures. I can feed those failure logs back to the AI: “The integration tests failed with XYZ, let’s debug this.” It turns bug-fixing into a collaborative loop with quick feedback, which AIs handle quite well (they’ll suggest a fix, we run CI again, and iterate).</p>
<p>Automated code quality checks (linters, type checkers) also guide the AI. I actually include linter output in the prompt sometimes. If the AI writes code that doesn’t pass our linter, I’ll copy the linter errors into the chat and say “please address these issues.” The model then knows exactly what to do. It’s like having a strict teacher looking over the AI’s shoulder. In my experience, once the AI is aware of a tool’s output (like a failing test or a lint warning), it will try very hard to correct it - after all, it “wants” to produce the right answer. This ties back to providing context: give the AI the results of its actions in the environment (test failures, etc.) and it will learn from them.</p>
<p>AI coding agents themselves are increasingly incorporating automation hooks. Some agents will refuse to say a code task is “done” until all tests pass, which is exactly the diligence you want. Code review bots (AI or otherwise) act as another filter - I treat their feedback as additional prompts for improvement. For example, if CodeRabbit or another reviewer comments “This function is doing X which is not ideal” I will ask the AI, “Can you refactor based on this feedback?”</p>
<p>By combining AI with automation, you start to get a virtuous cycle. The AI writes code, the automated tools catch issues, the AI fixes them, and so forth, with you overseeing the high-level direction. It feels like having an extremely fast junior dev whose work is instantly checked by a tireless QA engineer. But remember, <em>you</em> set up that environment. If your project lacks tests or any automated checks, the AI’s work may slip through with subtle bugs or poor quality until much later.</p>
<p>So as we head into 2026, one of my goals is to bolster the quality gates around AI code contribution: more tests, more monitoring, perhaps even AI-on-AI code reviews. It might sound paradoxical (AIs reviewing AIs), but I’ve seen it catch things one model missed. Bottom line: <strong>an AI-friendly workflow is one with strong automation - use those tools to keep the AI honest</strong>.</p>
<h3><strong>Continuously learn and adapt (AI amplifies your skills)</strong></h3>
<p><strong>Treat every AI coding session as a learning opportunity - the more you know, the more the AI can help you, creating a virtuous cycle.</strong></p>
<p>One of the most exciting aspects of using LLMs in development is how much <em>I</em> have learned in the process. Rather than replacing my need to know things, AIs have actually exposed me to new languages, frameworks, and techniques I might not have tried on my own.</p>
<p>This pattern holds generally: if you come to the table with solid software engineering fundamentals, the AI will <strong>amplify</strong> your productivity multifold. If you lack that foundation, the AI might just amplify confusion. Seasoned devs have observed that LLMs “reward existing best practices” - things like writing clear specs, having good tests, doing code reviews, etc., all become even more powerful when an AI is involved. In my experience, the AI lets me operate at a higher level of abstraction (focusing on design, interface, architecture) while it churns out the boilerplate, but I need to <em>have</em> those high-level skills first. As Simon Willison notes, almost everything that makes someone a <strong>senior engineer</strong> (designing systems, managing complexity, knowing what to automate vs hand-code) is what now yields the best outcomes with AI. So using AIs has actually pushed me to <strong>up my engineering game</strong> - I’m more rigorous about planning and more conscious of architecture, because I’m effectively “managing” a very fast but somewhat naïve coder (the AI).</p>
<p>For those worried that using AI might degrade their abilities: I’d argue the opposite, if done right. By reviewing AI code, I’ve been exposed to new idioms and solutions. By debugging AI mistakes, I’ve deepened my understanding of the language and problem domain. I often ask the AI to explain its code or the rationale behind a fix - kind of like constantly interviewing a candidate about their code - and I pick up insights from its answers. I also use AI as a research assistant: if I’m not sure about a library or approach, I’ll ask it to enumerate options or compare trade-offs. It’s like having an encyclopedic mentor on call. All of this has made me a more knowledgeable programmer.</p>
<p>The big picture is that <strong>AI tools amplify your expertise</strong>. Going into 2026, I’m not afraid of them “taking my job” - I’m excited that they free me from drudgery and allow me to spend more time on creative and complex aspects of software engineering. But I’m also aware that for those without a solid base, AI can lead to Dunning-Kruger on steroids (it may <em>seem</em> like you built something great, until it falls apart). So my advice: continue honing your craft, and use the AI to accelerate that process. Be intentional about periodically coding without AI too, to keep your raw skills sharp. In the end, the developer + AI duo is far more powerful than either alone, and the <em>developer</em> half of that duo has to hold up their end.</p>
<h3><strong>Real-Case Workflows</strong></h3>
<p><a href="https://blog.algomaster.io/p/using-ai-effectively-in-large-codebases">https://blog.algomaster.io/p/using-ai-effectively-in-large-codebases</a></p>
<p><a href="https://boristane.com/blog/how-i-use-claude-code/?utm_source=substack&amp;utm_medium=email">https://boristane.com/blog/how-i-use-claude-code/?utm_source=substack&amp;utm_medium=email</a></p>
<h1>Noted Things</h1>
<h2>Some Key Notes</h2>
<ul>
<li><p>Use llms.txt pages: <a href="https://llmstxt.org/">https://llmstxt.org/</a></p>
</li>
<li><p>MCPs: <a href="https://mcpmarket.com/server">https://mcpmarket.com/server</a>, <a href="https://github.com/upstash/context7#installation">https://github.com/upstash/context7#installation</a>, <a href="https://github.com/vercel/next-devtools-mcp">https://github.com/vercel/next-devtools-mcp</a>, <a href="https://github.com/ChromeDevTools/chrome-devtools-mcp">https://github.com/ChromeDevTools/chrome-devtools-mcp,</a> <a href="https://docs.sentry.io/ai/mcp/">https://docs.sentry.io/ai/mcp/</a>, <a href="https://github.com/GLips/Figma-Context-MCP">https://github.com/GLips/Figma-Context-MCP</a></p>
</li>
<li><p>Claude prompting best practices: <a href="https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-4-best-practices">https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-4-best-practices</a></p>
</li>
<li><p>Open AI prompting best practices: <a href="https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-the-openai-api">https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-the-openai-api</a></p>
</li>
<li><p>Vercel Skills: <a href="https://skills.sh/anthropics/skills/pptx">https://skills.sh/anthropics/skills/pptx,</a> <a href="https://github.com/vercel-labs/agent-skills/blob/main/skills/react-best-practices/SKILL.md">https://github.com/vercel-labs/agent-skills/blob/main/skills/react-best-practices/SKILL.md</a></p>
</li>
<li><p>AI agent real UI component knowledge — best practices, layout patterns, and design-system conventions for 60+ interface components: <a href="https://github.com/carmahhawwari/ui-design-brain/tree/main">https://github.com/carmahhawwari/ui-design-brain/tree/main</a></p>
</li>
<li><p>If GitHub Copilot can't fix a bug after 3 tries, stop. You're making it worse.<br />Here's what most devs do - they paste the error message back into the chat. Agent tries something. Doesn't work. Paste the new error. Agent tries again. Doesn't work. You're now 10 messages deep and your code is more broken than when you started.<br />This happens because the context window is poisoned. The agent is so fixated on its previous failed attempts that it's basically guessing at this point.<br />Here's what you do instead. When the agent gets stuck, don't give it another error message. Give it a job<br />Say exactly this: "Add whatever logging we need to reproduce this bug."<br />The agent knows your codebase. It'll drop console statements in exactly the right places - the ones it actually needs to understand what's happening.<br />Not random logging. Strategic logging.<br />The agent can't fix what it can't see. Give it visibility first, then ask for the fix. Works every single time.</p>
</li>
</ul>
<h1>References</h1>
<p><a href="https://craftbettersoftware.com/p/the-vibe-coding-stack-for-2026?utm_source=post-email-title&amp;publication_id=1295183&amp;post_id=178785780&amp;utm_campaign=email-post-title&amp;isFreemail=true&amp;r=2d5wj&amp;triedRedirect=true&amp;utm_medium=email">https://craftbettersoftware.com/p/the-vibe-coding-stack-for-2026</a></p>
<p><a href="https://blog.bytebytego.com/p/how-cursor-shipped-its-coding-agent?utm_source=post-email-title&amp;publication_id=817132&amp;post_id=185516568&amp;utm_campaign=email-post-title&amp;isFreemail=true&amp;r=2d5wj&amp;triedRedirect=true&amp;utm_medium=email">https://blog.bytebytego.com/p/how-cursor-shipped-its-coding-agent</a></p>
<p><a href="https://medium.com/vibe-coding/the-concept-every-ai-coder-learns-too-late-c63dd872f923">https://medium.com/vibe-coding/the-concept-every-ai-coder-learns-too-late-c63dd872f923</a></p>
<p><a href="https://github.blog/ai-and-ml/github-copilot/how-to-write-a-great-agents-md-lessons-from-over-2500-repositories/">https://addyo.substack</a><a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents">.co</a><a href="https://simonwillison.net/2025/Oct/7/vibe-engineering/">m/p/ho</a><a href="https://addyo.substack.com/p/how-to-write-a-good-spec-for-ai-agents">w-to-write-a-good-spec-for-ai-agents</a></p>
<p><a href="https://www.aihero.dev/a-complete-guide-to-agents-md#what-goes-where">https://www.aihero.dev/a-complete-guide-to-agents-md#what-goes-where</a></p>
<p><a href="https://substack.com/home/post/p-188588325?source=queue">https://substack.com/home/post/p-188588325?source=queue</a></p>
<p><a href="https://awesomeneuron.substack.com/p/a-visual-guide-to-ai-agents">https://awesomeneuron.substack.com/p/a-visual-guide-to-ai-agents</a></p>
<p><a href="https://medium.com/data-science-collective/stop-prompting-start-designing-5-agentic-ai-patterns-that-actually-work-a59c4a409ebb">https://medium.com/data-science-collective/stop-prompting-start-designing-5-agentic-ai-patterns-that-actually-work-a59c4a409ebb</a></p>
]]></content:encoded></item><item><title><![CDATA[Senior Front-end Engineer Interview Handbook]]></title><description><![CDATA[List of the Technical Questions
Programming Languages (JavaScript/TypeScript)
What is a closure in JavaScript, and how does it work?
As you know, JavaScript functions can be nested within each other, ]]></description><link>https://blog.tuanhadev.tech/senior-front-end-engineer-interview-handbook</link><guid isPermaLink="true">https://blog.tuanhadev.tech/senior-front-end-engineer-interview-handbook</guid><category><![CDATA[interview]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Sun, 11 Jan 2026 12:52:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/boCDlcZvaJI/upload/ee74b0eac02fe273599d6f4ba3159dc9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>List of the Technical Questions</h1>
<h2>Programming Languages (JavaScript/TypeScript)</h2>
<p><strong>What is a closure in JavaScript, and how does it work?</strong></p>
<p>As you know, JavaScript functions can be nested within each other, which creates a hierarchy of scope. Each function has its own local variables and is able to access the variables from the outer function. Closure is a powerful JavaScript feature that allows a function to access the outer scope even if the outer function is already finished executing. For example, you define a new createCounter() function. This function contains a variable called counter and returns a new function called calculateFunction that returns counter++. Even after the createCounter() function is finished executing, the calculateFunction is still able to access the counter variable. That’s how the JavaScript closure works.</p>
<pre><code class="language-javascript">function createCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
</code></pre>
<p><strong>What is hoisting in JavaScript, and how does it work with const and let?</strong></p>
<p>Hoisting is a feature that JavaScript will hoist the variables to the top of the global scope. For example, when you try to log a variable above the line where it was defined, then JavaScript will log undefined without throwing any errors. Most programmers only think that the hoisting feature only works with the var variable and doesn’t work with the const and let variables because they see JavaScript throw an error when they do that. But the truth is, you should notice the error JavaScript throws. When you try to log let, const variables before initialization, then the error message will be “Can not access before initialization, “ but when you try to log a variable that is not defined, then the error will be “Variable is not defined“. That means JavaScript knows the variable but doesn’t automatically initialize a value for that variable as it does with a var variable.</p>
<h2>Modern Front-end Frameworks (React.js/Next.js)</h2>
<p><strong>Can you explain how the React Rendering Process works under the hood?</strong></p>
<p>I already published a detailed explanation about this topic on my blog. In short, when a React Component is rendered, it goes through two main phases: the render phase and the commit phase. On the render phase, React will create a new virtual DOM by converting the React component to JSX and then to a React Element, and the final result is a new Virtual DOM. When we have a new Virtual DOM, React will start to compare the new one with the previous one by using React’s Reconciliation mechanism to figure out the list of changes that need to be updated to the actual DOM. Now React knows exactly the changes that need to be made, which is why we don’t need to update the full DOM when a state update happens. Next to the commit phase, React will start to commit to the DOM based on the list of changes we have in the render phase by calling the DOM API like (createElement, setAttribute, appendChild,…), and the useEffectLayout will run after that. When the commit to the DOM process is done, it is time for the browser to work by executing the calculate layout, paint, and composite, so I will not talk about it. When the browser’s work is done, it’s time for the micro queue of useEffect to run. That is how React works under the hood.</p>
<p><strong>What is the difference between a controlled and an uncontrolled component?</strong></p>
<p>A controlled component is a component that React will be in charge of managing the behavior of the component by using state.</p>
<p>On the other side, an uncontrolled component is a component that just lets the DOM manage its own states by using refs.</p>
<p>A controlled component is mostly used in the project because it allows more controls and predictable behaviours.</p>
<p>In opposite, if your component is just a file upload input, no need for validations, no need for dependencies, then an uncontrolled component is preferred.</p>
<p><strong>Can you explain the difference between useEffect and useLayoutEffect?</strong></p>
<p>The main difference between useEffect and useLayoutEffect is when those functions are called and their purpose. Those are all running in the commit phase, but the useLayoutEffect is run before the browser paints process, while the useEffect runs after the browser paints. Also, the useLayoutEffect runs the code in a synchronous way, while the useEffect runs the code in an asynchronous way. That’s why React recommends you should be careful when using useLayoutEffect because the code run inside the useLayoutEffect will block the rendering process. React recommends we should use useLayoutEffect when we need to handle an immediate task relevant to DOM measurement, calculating the element’s position to prevent flicker, and use useEffect when we need to handle side effect tasks.</p>
<p><strong>Can you list down all the factors that make the component re-render?</strong></p>
<p>Well, that is the interesting question, but it takes quite take time to answer. Firstly, I think we should understand that React’s re-render happens when React needs to update the UI with some new data. Necessary re-renders themself are not the problem, but too much unnecessary re-renders are the big problem for the performance. There are four reasons why a component would re-render itself: state changes, parents re-render, props change, context changes, and hook changes.</p>
<ul>
<li><p>When the state changes, the component would re-render itself</p>
</li>
<li><p>When a parent component re-renders, then all of its children will also re-render. It always goes down the tree; the re-render of a child component doesn’t trigger the parent component's re-renders.</p>
</li>
<li><p>When props change, they are mostly updated by the parent component. That means the parent component would have to re-render and trigger all of its component re-renders regardless of its props.</p>
</li>
<li><p>When a value of the Context Provider changes, then all the components that use this context will re-render, even if that component doesn’t use the changed portion of the data directly.</p>
</li>
<li><p>Everything that happens inside a hook belongs to the component that uses it. That means the same rules regarding State and Context apply here. And, we should notice that the hook can be chained; the same rules apply to all of them.</p>
</li>
</ul>
<p><strong>How many approaches do you know that we can use to prevent unnecessary re-rendering?</strong></p>
<p>Wow, that is a big question. There are many ways we could use to prevent unnecessary re-rendering. Firstly, we should understand that unnecessary re-renders themself are not actually a big problem. React is fast and able to deal with them without users noticing anything. However, if it happens too often and on a heavy component, then that could cause the performance issue to end users.</p>
<ul>
<li><p>We should avoid creating a new component inside other components. On every re-render, React will re-mount the component (destroy it and recreate it from scratch), which is going to be much slower than the normal render.</p>
</li>
<li><p>We should move the state down as close to the component that consumes it. For example, instead of putting open/close dialog state on the parent component, we should move it down to the dialog component, then every time the state changes, only the dialog component will be re-rendered, not affecting the parent component</p>
</li>
<li><p>We should encapsulate the state changes into a smaller component by passing slow components as props. Because the props are not affected by the state changes, heavy components won’t re-render.</p>
</li>
<li><p>We can prevent unnecessary re-renders by using React.memo, useMemo, useCallback</p>
</li>
<li><p>We also need to implement the React key in the correct way if we don’t want our elements to be re-rendered every time.</p>
</li>
<li><p>We can prevent re-renders caused by Context with those techniques, like memoizing context value, splitting data into chunks, and context selectors</p>
</li>
</ul>
<p>Those are all the techniques that I can remember right now for preventing unnecessary re-renders in React.</p>
<p><strong>Can you explain exactly the usage of useMemo and useCallback, and when we should avoid them?</strong></p>
<p>Most of the Front-end engineers know about the usage of those memoized React hooks like useMemo and useCallback. The useMemo hook is used to memoize a value when that value requires a heavy calculation. The useCallback hook is used to memoize a function. But they don’t actually understand how these functions work under the hood and how to implement them correctly to prevent heavy components from re-rendering. I used to like them and blindly used those hooks without understanding. React only uses value to compare if the prop is a primitive value; if the prop is an object or a function, React will use reference to compare. That is why we need to memoize the function and the object prop type. For example, if I already memoized the heavy value and pass it as a prop to a child component, the child component still re-renders if we don’t wrap the child inside React.memo function. Also, if we want to put an object or a function into the dependency array of useEffect, we have to memoize them first if we don’t want useEffect to always re-run. And, we shouldn’t overuse these React memoized functions because the memoization is not free, it adds a few extra works like storing previous value, comparing the dependency array,… in every re-render. We should only use it when it is actually needed.</p>
<p><strong>What are React keys used for, and what happens if we don’t use them correctly?</strong></p>
<p>React’s key is the mechanism that allows React to control the rendering process by identifying which element of a list has changed and needs to be re-rendered. The React key needs to be both unique and static. The best practice is to use the id property in each item as a key, or we could use the index of the array as a key if that array can’t be modified (but we don’t recommend that way). If you don’t use the React key in the correct way, like using <code>Math.random()</code>, it will be a disaster for the performance of the website. You will destroy the most important DOM reconciliation mechanism of React and will make the whole array element re-render, causing some mysterious UI bugs that are really hard to trace.</p>
<p><strong>How does React’s reconciliation process work?</strong></p>
<p>Well, that is an interesting question that requires a deep understanding of how React works under the hood. React’s reconciliation process is a really important mechanism in React that allows React to compare the Virtual DOM to figure out specific changes that need to be made to the actual DOM. That technique made React re-render elements efficiently, only re-rendering the changed parts instead of re-rendering the whole DOM. React’s reconciliation algorithm is based on two simple assumptions:</p>
<ul>
<li><p>Two elements of different types will produce two different trees. For example, if an element changes from the span into the div, then React will assume that everything inside has changed and rebuild the entire subtree. And, if the element tag is not changed, then React will start comparing props and states. React does a shallow comparison so you have to use those memo techniques if you don’t want that element will be re-rendered</p>
</li>
<li><p>The React key provides stability hints: React requires us to provide a key for each item element when we want to build a listing. By doing that, React will know exactly which item on that list has changed, been added, deleted, or no changes need to be made.</p>
</li>
</ul>
<p><strong>Tell me what you know about CSR?</strong></p>
<p>Client-side rendering is the strategy where the server only sends the minimum HTML to the client, and the data fetching, templating, and routing required to display content for the page are handled by JavaScript that executes on the browser. Almost all of the UI is generated on the browser. The entire application is loaded on the first request. CSR enables the creation of a Single-Page application that supports navigation without page refreshes and provides a great user experience. As the user navigates to another page by clicking a link, there is no request to the server to generate a new page; the code runs on the client to change the view/data. While CSR provides a rich interactive experience after the initial load, it has the well-known drawback of negatively impacting first-page load performance and SEO, which means users must see a blank page before the large JavaScript bundle is fully downloaded and executed.</p>
<p><strong>Tell me what you know about SSR?</strong></p>
<p>SSR is one of the oldest methods of rendering web content, where the HTML is rendered on the server and sent to the client browser as a response. With SSR, every request is treated individually and will be processed as a new request to the server. It helps to reduce the JavaScript bundle size sent to the browser and improve the user experience by reducing the time for the page content to be visible. We still have to wait for the data to be fetched and pre-rendered on the server before sending it to the client, and also wait for the hydration process to be finished before the user can interact with the UI.</p>
<p><strong>Tell me what you know about SSG?</strong></p>
<p>SSG comes to resolve the weakness of SSR by moving the rendering HTML process from the runtime to the build time and serving the page as a static site. For example, when users request a page, that page is already generated at build time and is served as a static file by CDN or served from cache. That static file is immediately sent to the browser without waiting for data to be fetched, waiting for HTML to be prepared, and users can see the page instantly. SSG is ideal for the static content.</p>
<p><strong>Tell me what you know about ISG?</strong></p>
<p>As you know, SSG is only suitable for static content. It has limitations for applying to dynamic content or content that changes frequently. The Incremental Static Generation was introduced as an upgrade to SSG. It allows for refetching new content in the background at a period of time and automatically applies it to the old one without the need for a full rebuild. Once generated, the new version of the static file becomes available and will be served for any new requests in subsequent minutes.</p>
<p><strong>What are Suspense and Streaming in React?</strong></p>
<p>In the normal SSR implementation, the server will wait to generate all the HTML it is going to as a string and send it to the client as a big chunk. That made you have to wait for all the data for the entire page to prepare before you can see, hydrate, and interact with anything.</p>
<p>With streaming SSR implementation, the server will first create a <a href="https://nodejs.org/api/stream.html">Node.js stream</a>. Then, it will use <a href="https://react.dev/reference/react-dom/server/renderToPipeableStream">renderToPipeableStream</a> to render the React app chunk by chunk into that Node stream. It lets React “flush whatever parts of HTML are ready and postpone slow parts for later“</p>
<p>The chunk boundaries for this process are those components that are wrapped by . Whenever you wrap a component with , that means you tell React not to wait for the data of this component, and start streaming HTML for the rest of the page, and show the fallback UI for that component instead.</p>
<p><strong>What are Server Components?</strong></p>
<p>The biggest issue with SSR is “no interactivity gap“. While SSR helps reduce the load time for the initial load but users need to wait and can’t interact with it until the hydration process is finished. RSCs were introduced at React 18 to allow you to render part of the UI on the server ahead of time without sending any JavaScript to the browser, dramatically shrinking client bundles. RSCs are rendered on the server and send a special data format called the React Server Component Payload to the browser. The client-side React runtime then uses the payload to hydrate HTML. The Container/Presentation pattern is a great candidate for RSCs, while the container component could be an RSC that fetches data and passes it as props to the presentational client component, meaning the fetching logics never ship to the browser.</p>
<p><strong>Will React Server Components replace the SSR?</strong></p>
<p>No. RSCs do not replace SSR. They complement it. In practice, we can still do SSR for the initial render, but many components can be RSC then significantly reduces the JavaScript needed to ship to the browser.</p>
<p>There are a few differences between SSR and RSCs:</p>
<ul>
<li><p>Code of the RSC is never sent to the browser, while on some implementations of SSR, their code is still included in the JavaScript bundle and sent to the browser.</p>
</li>
<li><p>SRCs enable access to the back end everywhere on the tree. But on the SSR implementation, for example, in Next.js. We have to fetch all of the data via getServerSideProps, which has limitations of only working on the top of the page.</p>
</li>
<li><p>SRCs may be refetched in the background while maintaining the client-side state of the tree. This is because the main transport mechanism is richer than just pain HTML that allows re-fetch on the server parts without blowing up the client state, such as search input text, focus.</p>
</li>
</ul>
<p><strong>How does React insert real data into a streaming component?</strong></p>
<p>For the first render, React will send the fallback UI, like the loading skeleton, immediately to the user and attach an ID to that element while waiting for the actual data to be loaded and streamed. Once it’s ready, React includes it in the ongoing HTML stream, along with the lightweight JavaScript that handles the magic: replace the new actual data with the old placeholder based on the ID we attached before. This makes this transition feel smooth and effortless to the user due to no full rerenders, no flicker, just progressive enhancements. It’s a part of the internal React streaming process, not something that we can handle manually. But understanding it helps connect the dots between the fallback we see on the screen and seamlessly be replaced by the real content.</p>
<p><strong>What are the hydration, Progressive hydration, and Selective Hydration? How does the selective hydarion solve the pain points of traditional hydaration?</strong></p>
<p>In the traditional SSR rendering before React 18, when the user first sees the page, the user can’t interact with the page, such as clicking on a button, or see any animations. The user needs to wait for the JS bundle of the whole page to be loaded and executed before they can become responsive to interaction. The hydration is the process that the browser attaches event handlers and everything to the DOM, which makes the page become interactive. This process takes a while, so users have to wait.</p>
<p>Progressive hydration is a new approach that was released in React 18 for resolving the pain point of traditional hydration. Instead of hydrating the entire page at once, we can also progressively hydrate the DOM nodes. Progressive hydration makes it possible to individually hydrate nodes over time, which makes it possible to only request the minimum necessary JavaScript. It delays hydration of the less important parts of the page, like those parts that aren’t visible in the first viewport. On the downside, progressive hydration may not be suitable for a dynamic app where every element on the screen is available to the user and needs to be made interactive on load.</p>
<p>The selective hydration is a new hydration mechanism that was introduced in React 18, along with a progressive hydration approach. Besides trying to hydrate as soon as possible based on the DOM tree, it prioritizes what matters most to the user — the parts they touch. This creates an illusion of instant hydration because interactive components are hydrated first, even if they are deeper in the component tree. For example, both the blog component and header component could stream on the server independently. By default, React starts with the first Suspense boundary it encounters in the tree — it’s header component in this case. But, imagine users click on the blog section before it is hydrated. Instead of waiting for the header component to finish, React intercepts the event during the capture phase and synchronously hydrates the blog section first, so the interaction works immediately.</p>
<p><strong>How do you structure a large-scale React application for scalability and maintainability?</strong></p>
<p>That is a big question that takes a lot of time to fully answer. There are a few important points that I constantly follow up on when I am setting up a large-scale React application:</p>
<ul>
<li><p>Firstly, I organize files not just by technical roles, but also by domain responsibilities. Organizing files based on technical roles might be fast at the start. But when the application grows, updating things like cart features, we need to go through multiple folders, such as components/, stores/, and utils/. This separation slows you down and creates mental overhead. On the other hand, when grouping components by domain responsibilities, everything related to the feature lives in one folder. Features become self-contained, refactoring becomes safer, and your team grows; each squad might handle different domains without tight coupling and conflicts with each other. This clear boundary makes parallel development much easier. Teams can refactor their own features without worrying about breaking others.</p>
</li>
<li><p>I always prefer to create a dedicated common module for all generic components and utilities used across different pages and modules. This helps avoid redundancy and promotes reusability across the application.</p>
</li>
<li><p>For each module, I apply the Locality of Behaviour principle by keeping things as close to where they are used. For example, I locate child components, hooks, and utils near where they are used within the application. This strategy improves readability and maintainability as when a developer works on a feature, they have all the related files in proximity, which makes it easier to understand and maintain.</p>
</li>
<li><p>I also apply Layered Architecture with the Separation of Concerns Principle (refer to the next questions for better explanation)</p>
</li>
<li><p>Furthermore, I also apply the Atomic Design Pattern for managing the growing complexity of component structures (refer to the next question)</p>
</li>
</ul>
<p><strong>Can you tell me more about the Layered Architecture with Separation of Concerns?</strong></p>
<p>When we design a Front-end application, it is better to split the application into multiple layers for easier management and to avoid causing bugs in unrelated parts. Most scalable Front-end systems can be thought of as layers, each with a purpose. Each layer has its own responsibilities and knows only as much as it needs. This separation creates clarity, reduces bugs, and increases developer speed. Commonly, we could split an application into 5 layers: UI Layer, Behavior Layer, State Management Layer, Services Layer, and Utilities/Core Logic Layer.</p>
<ul>
<li><p>The UI Layer should be predictable and reusable. No useEffect, no useState, just props in and UI out. It knows nothing about where data comes from, just receives props and renders markup.</p>
</li>
<li><p>The Behavior Layer is where the logic lives. It lives in a custom hook and is responsible for local states, effects, and interaction logics. We can plug the same behavior for different UIs without duplicating a line of logic.</p>
</li>
<li><p>The State Management Layer is where we centralize shared states. When our app grows, we need a place to manage our shared state to be shared across components. We can use React Context for small apps and other popular libraries, such as Redux and Zustand, for large apps</p>
</li>
<li><p>The Service Layer is where we are talking with the outside world. This layer is our interface with APIs, storage, and anything that lives outside of the app.</p>
</li>
<li><p>The Utilities/Core Logic Layer is where shared helpers, validation functions, formatters, and pure logic reside.</p>
</li>
</ul>
<p><strong>What is the Atomic Design Pattern?</strong></p>
<p>When we build scalable applications in React, we often encounter challenges in managing the growing complexity of component structures. The Atomic Design Pattern has emerged as a powerful methodology for organizing and structuring applications. This pattern suggests breaking down the interface into multiple fundamental building blocks, promoting a more modular and scalable approach to application design.</p>
<p>The Atomic Design Methodology breaks down design into 5 distinct levels:</p>
<ul>
<li><p>Atoms: These are basic building blocks of an application, such as inputs, buttons, etc.</p>
</li>
<li><p>Molecules: Molecules are groups of atoms that are combined together to form a functional unit, such as a search feature that includes a label, an input, and a submit button.</p>
</li>
<li><p>Organisms: Organisms are relatively complex UI components composed of groups of molecules and atoms, such as a header of a page.</p>
</li>
<li><p>Templates: Templates are page-level objects that place components into a layout. They usually consist of groups of organisms, representing a complete layout.</p>
</li>
<li><p>Pages: Pages are specific instances of templates that show what a UI looks like with real data.</p>
</li>
</ul>
<p>The Atomic Design Pattern aligns perfectly with React’s component-based architecture and brings a lot of benefits, such as promoting reusability, ensuring consistency, etc. While it provides many benefits, we should be cautious not to over-engineer and introduce unnecessary complexity.</p>
<p><strong>How many React patterns do you know?</strong></p>
<p>Well. There are several popular React patterns that we can apply in our React code to make it more optimized, readable, and maintainable, such as the Higher Order Pattern, Render Props Pattern, Container/Presentation Pattern, Hooks Pattern, and Compound Pattern.</p>
<ul>
<li><p>A HOC is a component that receives another component. The HOC contains a certain logic that we want to apply to the other component by passing that component as a parameter. This pattern allows us to share the same logic throughout multiple components. For example, when we want to apply a custom loading logic called useLoading to multiple components, we can apply HOC.</p>
</li>
<li><p>Another way of making components more reusable is by applying the Render Props Pattern. A Render Prop is a prop on a component whose value is a function that returns JSX. The component itself does not render anything, but calls the render prop.</p>
</li>
<li><p>In React, one way to enforce separation of concerns is by using the Container/Presentation Pattern. With this pattern, we can separate the view from the logic. For example, when we want to create a component to display a list of products, container components are responsible for fetching the data, formatting it, and passing the data as props to the presentational components to show.</p>
</li>
<li><p>Hooks were the new feature that was released on React 16.8. Although Hooks are not necessarily a design pattern but they play a very vital role in React applications. The traditional ways to share code across multiple components are by using HOC and the Render Props Pattern. Although both patterns are still valid and good practice but Hooks mostly replaced them.</p>
</li>
<li><p>The Compound pattern is really useful when we have to deal with multiple components that belong to each other through a shared state. The Compound Component Pattern allows you to create a component that all work together to perform a task. For example, when we want to create a custom complex select component that contains multiple select items and other sub-components.</p>
</li>
</ul>
<p><strong>How can you structure state management architecture for a large-scale application?</strong></p>
<p>Not all states are the same, so instead of treating it as one thing, we should clarify it into layers, with its own natural place in the application.</p>
<ul>
<li><p>The local state should stay local, and we should keep it as close as possible to where it is used. For example, a simple open/close state of a modal should be local and not belong to Redux or Context. Components died, local states died</p>
</li>
<li><p>Server States are anything that originates from the external sources, like API responses, data from the backend. It usually comes with its own complexities (state data, retries, invalidation), so it should be treated as a dedicated layer. That is exactly why tools like React Query, Apollo, or SWR exist. They handle caching, refetching, and synchronization for us, allowing client state to remain cleanly separate from server data.</p>
</li>
<li><p>Everything that is happening in the website’s URL is a state in a way, then we can treat it as a separate layer. For example, we can pass some queries or parameters to reflect the UI. When the URL changes, then the UI changes. These days, some of the routers also provide built-in methods like useSearchParams for you to easily manage the URL states, or you can use a popular library like nuts instead</p>
</li>
<li><p>Not all states can stay isolated. Sometimes, data has to move beyond a single component. That’s where the shared state layer comes in. But the shared client state needs boundaries. And we should follow the simple principle that “The State should rise only as high as its consumers require“. If it is just shared between siblings, prop drilling, then a small Context is perfectly fine. If it cuts across multiple features or pages, then it earns its place in a dedicated store like Redux, Zustand.</p>
</li>
</ul>
<p>By drawing these lines, the decision of how to manage a state becomes clearer.</p>
<p><strong>Can you explain what React Context is and how it works?</strong></p>
<p>As we know, when a React app grows then the amount of state grows. Additionally, React uses one-way data flow, which means data can only go down the component tree, making passing state between components at the same level a really hard task. If we don’t manage it properly in time, it could lead to uncontrolled data flow, causing props drilling issues, and making it harder to debug. React Context is a built-in mechanism that creates a kind of “global store“ for specific parts of the application. React Context allows us to pass data through the component tree without manually passing props through immediate components. However, while Context is a great choice for providing access to data, it has some limitations, such as Context does not provide a standardized way to modify states, and it becomes harder to track where state changes occur because we have multiple contexts that wrap different parts of the project.</p>
<p><strong>Can you list a few ways to optimize React Context?</strong></p>
<p>We all know React Context allows us to pass the props from a component to other deep components in the React tree without passing props through multiple components. Passing data in this way can improve the performance of our React app by avoiding the re-rendering of components in between. However, it could be dangerous if we don’t manage it properly because all components that consume state from the Context Provider will be re-rendered if a state in the Provider gets updated. Even if components do not consume the changed parts, there are no standard memorization techniques that can prevent it. Below are some techniques that we can use to optimize the usage of React Context:</p>
<ul>
<li><p>To minimize the React Context re-renders, we should always memoize the value we pass to the Context Provider.</p>
</li>
<li><p>We can split from one provider to multiple providers to further minimize re-renders. Switching from useState to useReducer can help with this.</p>
</li>
<li><p>Even though we don’t have the proper selectors for Context like Redux, we can use the trick by combining the Higher-Order Function and <code>React.memo</code>.</p>
</li>
</ul>
<p><strong>What is Redux, and how does it work?</strong></p>
<p><strong>Redux</strong> is a state management library that implements ideas inspired by the Flux architecture. It ensures a one-way data flow that makes the application state flow more predictable and easier to track.</p>
<p>Redux introduces a more structured approach with clearly defined elements:</p>
<p>A <strong>Store</strong> element holds the entire application state in a single object and manages dispatching actions. The logic for how state changes is defined in reducers, not in the store itself.</p>
<p><strong>Action</strong> elements are plain JavaScript objects that describe what happened in the application.</p>
<p><strong>Dispatch</strong> is a function that sends actions to the store and starts the update process.</p>
<p><strong>Reducer</strong> elements are pure functions that take the previous state and an action and return the next state.</p>
<p><strong>Selector</strong> elements are functions that read or derive specific pieces of data from the Redux state.</p>
<p>And the standard Redux flow is:</p>
<p>The user interacts with the view, then creates an action by clicking on a button → The action is dispatched to send the action to the store → The store receives the action and passes it to the reducers → The reducer receives the action and previous state and returns a new state → The store replaces the old state with the new state returned by the reducers → Components use selectors to read the updated state and re-render.</p>
<p><strong>What are the differences between React Context and Redux?</strong></p>
<p>Well. React Context is a built-in feature of React, while Redux is an external library inspired by the Flux architecture. They are both developed by the React team and provide abilities for managing global state across the application. React Context is more suitable for a small app, or when we just need to share the state across multiple components in the hierarchy. On the other hand, Redux is a preferred choice for managing state in a large application where we need to share the state across multiple features or pages. Additionally, React Context is only good for providing access to data and does not provide a standardized way to modify states. Also, it becomes harder to track where state changes occur since we have multiple Contexts that wrap different parts of the project. In contrast, Redux introduces a more structured approach with defined elements such as (Store, Reducer, Dispatchers, Actions,….) and ensures one-way data flow that makes the state flow of the application more predictable and easier to track.</p>
<p><strong>Can you explain the approach for managing complex global state?</strong></p>
<p>For managing a complex global state, where using React Context is not enough, I will look into state management libraries, such as Redux, Zustand, Jotai, and MobX. Honestly, I haven’t joined any business projects that applied those libraries before. I used to apply Redux and MobX to my pet project for learning a few years ago. I worked with the React Context mostly because it is enough. I do know the Flux architecture and the core data flow of Redux. There is a pattern that I have read somewhere that: “A State should rise only as high as its consumers require“. We should keep the boundaries clear and avoid both over-engineering and unnecessary sprawl.</p>
<p><strong>What is useEffect? How do you use it in the project?</strong></p>
<p>As its core, useEffect is a powerful hook that runs after the browser’s paint process. This hook allows us to perform side-effect tasks that go beyond the pure render logic, such as API calls and DOM mutations. Because it’s about keeping React components in sync with something outside of React, so if we are using useEffect to synchronize one piece of React state to another piece, we are doing it wrong. We should treat useEffect as the last option instead of the first option.</p>
<p><strong>What do you care about data fetching on the client?</strong></p>
<p>Nowadays, instead of writing a lot of code for fetching data over the network, to cover various aspects such as error handling, caching, and canceling requests. We have several libraries that will handle almost everything for us, like axios, swr, and tanstack query. But I do believe that the choice of technology doesn’t matter much here, and no library can improve the performance of the app by itself. I do focus on the fundamentals of data fetching and data orchestration patterns and techniques. I am aware of the browser limitations of parallel requests, prefetching critical resources even before React is initialized, and techniques for handling waterfalls and race conditions issues.</p>
<p><strong>What is the React Server Action?</strong></p>
<p>React Server Action is a way to write server-side code, the stuff usually handled by API Routes, that can now be written inside the React Component. In Next.js, we just need to add the directive “use server“at the top of the file to tell Next.js that this function should only be called on the server. The React Server doesn’t mean to replace the API Routes entirely; it’s a game-changer for tasks deeply tied to the UIs.</p>
<p><strong>How does Next.js Server Actions work under the hood?</strong></p>
<p>Firstly, to mark a function as a Next.js Server Action, we only need to put a “use server“ directly at the top of the file. By doing so, it will tell Next.js that every exported function in that file is a Next Server Action. When we call Server Actions on Client-side components, it is not just a regular function call. Next.js does some magic behind the scenes; it’s like an RPC(Remote Procedure Call) process. The flow will be: the client code calls the Server Action function =&gt; Next.js serializes arguments, converting them into a format that can be sent over the network =&gt; the POST request is fired off to the special Next.js endpoint =&gt; The server receives the request, deserializes arguments, and executes the code =&gt; When the process on the server is finished, the server then serializes the returned value and send it back to the client =&gt; The client receives the responses, deserializes it and automatically re-renders the relevant parts of the UI. The best part is no more manually refetching the data or updating the state after mutation. Next.js will automatically re-render the parts that need to be changed because of it.</p>
<p><strong>Can you list all the benefits of the Server Action?</strong></p>
<p>As we know, managing the communication between the client and the server is the real pain. Server Action comes to resolve that real pain by letting us put the server-side code right into the components. That makes things simpler, no more APi routes, no more re-fetching after mutation. React Server also boosts the performance by reducing those back-and-forth trips between the client and the server. Security is also another win when we put sensitive information like database queries and keys on the server.</p>
<p><strong>Can you list all the downsides of using the Server Action?</strong></p>
<p>While Server Actions bring a lot of benefits, it also has some downsides like any other technology. Below are some of them:</p>
<ul>
<li><p>One of the biggest issues is the potential for tight-coupling. By allowing the server logic to live right inside the component, it is easy to end up less modular and harder to maintain codebase. Changing the server logic might force the front-end to be updated.</p>
</li>
<li><p>The second one is a learning curve. While understanding the basic Server Action is simple, learning advanced things like serialization, caching, and error handling takes time.</p>
</li>
<li><p>The third issue is debugging. When something goes wrong with Server Action, we cannot just rely on the network tab of the Chrome Dev Tool. We need to get comfortable with debugging techniques on the server-side.</p>
</li>
<li><p>The last issue is about performance if we overuse React Actions. Each Server Action is a network request; if there are too many network requests, that could make things worse.</p>
</li>
</ul>
<p>Server Action is a powerful tool, but like other tools, it can be misused. It is best for data mutations and operations where the server logic tight couple with the UI and needs to be lived on the server.</p>
<p><strong>When should we use Server Actions?</strong></p>
<p>The Server Actions align perfectly with tasks like Performing Data Mutations. It allows performing server operations and database mutations without exposing the credentials and sensitive information to the client. It also dramatically reduces and simplifies the code by removing the need to write API routes for your operations.</p>
<p><strong>What are the potential pitfalls with Server Actions?</strong></p>
<p>While Server Actions bring us a lot of benefits, if we use them everywhere without understanding how it works, it could hurt our application’s performance. I could list some of the mistakes when we use Server Actions in the wrong way:</p>
<ul>
<li><p>For client-side fetching, Server Actions might not be the best option. They automatically use the POST requests, so the data can’t be cached like with the GET requests. Furthermore, Server Actions shouldn’t be used with the Server Components. Because using Server Actions here would delay the data availability, as it causes extra network requests.</p>
</li>
<li><p>Even though Server Actions handle server-side logic, under the hood, they are just another API route, and Next.js handles the POST requests automatically. Because of that, Server Actions do not hide the requests, and anyone can replicate them by using the Rest Client. That is why we should use proper authentication and authorization checks when working with sensitive data.</p>
</li>
<li><p>Using Server Action might be convenient, but every action comes at a cost. We should avoid using them everywhere and consider before using them. For tasks that could be easily handled on the client side, keep them on the client side.</p>
</li>
<li><p>When we need our API to be accessible to multiple clients, classic API routes might be a more appropriate solution. Imagine if we need the same logic for both web app and mobile app, duplicating the same Server Action logic will duplicate the work and make it complicated for maintenance.</p>
</li>
</ul>
<p><strong>Can you list some common mistakes when applying Server Actions?</strong></p>
<p>Server Actions help to simplify our code, reduce the code boilerplate, and look like the future of data mutations in Next.js. But if we don’t use it in the right way, it would cause a serious problem with our application’s performance.</p>
<ul>
<li><p>The most common mistake is not using the useTransition hook for the pending state. The user clicks on a submit button again and again, the Server Action is running, but the UI provides zero feedback. We need to wrap our action inside the useTransition to make the interface interactive and avoid users spamming the Submit button</p>
</li>
<li><p>The second mistake is that we are skipping validation on the client side. For example, it it so waste of resources if we trigger a Server Action and make the full network round trip to tell the user that they are missing a required field. It’s better to validate the input before passing it to Server Action.</p>
</li>
<li><p>The third mistake is that we are missing adding validateTag or validatePath after calling the Server Action. This mistake is not slowing the performance, but it will make the user still see the stale data after executing the data mutations. By adding those functions, it will tell Next.js to refetch the data that was changed, and the user can see the new data.</p>
</li>
<li><p>The fourth mistake is that we are importing the large client-side library into a server actions file. Server Actions are server-side code; they run in a Node.js environment. If we import a massive client-side library, we will get errors. And the solution is that we should choose the server-side compatible library.</p>
</li>
</ul>
<p><strong>What is a Route Group in Next.js, and what is it used for?</strong></p>
<p>A Route Group is a folder wrapped in parentheses (e.g., <code>(marketing)</code>) in the App Router. The parentheses signal to Next.js to <strong>exclude that segment from the URL path</strong>, so the folder exists purely in the file system. This lets you organize routes and share layouts without polluting the URL structure — for example, <code>(marketing)/about/page.tsx</code> still resolves to <code>/about</code>, not <code>/marketing/about</code>.</p>
<p><strong>What are the main use cases?</strong></p>
<ol>
<li><p><strong>Shared layouts without URL pollution</strong> — wrap related routes in a group with a common <code>layout.tsx</code>. For example, <code>(auth)</code> routes share a minimal layout with no nav, while <code>(app)</code> routes share a full shell with sidebar and header — all without those group names appearing in the URL.</p>
</li>
<li><p><strong>Code organization</strong> — group routes by feature, team, or domain (e.g., <code>(shop)</code>, <code>(blog)</code>, <code>(admin)</code>) purely for developer clarity. This is especially valuable in large codebases where a flat <a>app</a> directory becomes hard to navigate.</p>
</li>
<li><p><strong>Multiple root layouts</strong> — each group can define its own root <code>layout.tsx</code>, giving entirely different page shells to different sections of the app. This avoids messy conditional rendering inside a single root layout.</p>
</li>
</ol>
<p><strong>What is</strong> <code>unstable_cache</code> <strong>in Next.js?</strong></p>
<p><code>unstable_cache</code> is a Next.js utility that lets you <strong>cache the result of any async function</strong> — not just <code>fetch</code> calls. It wraps a function and stores its return value in the Next.js Data Cache, with support for cache tags, revalidation intervals, and on-demand invalidation via <code>revalidateTag</code>. The <code>unstable_</code> prefix signals it's a stable-enough API but still subject to change before a finalized name is given.</p>
<pre><code class="language-typescript">import { unstable_cache } from 'next/cache';

const getCachedUser = unstable_cache(
  async (id: string) =&gt; db.user.findUnique({ where: { id } }),
  ['user'],          // cache key parts
  { revalidate: 60, tags: ['users'] }
);
</code></pre>
<p><strong>Why is it necessary for non-fetch data sources?</strong></p>
<p>Next.js automatically caches and deduplicates <code>fetch</code> requests in Server Components. However, <strong>database queries, ORM calls, third-party SDKs, filesystem reads, or any non-HTTP data access bypass that cache entirely</strong> — they re-execute on every request by default. <code>unstable_cache</code> fills that gap by bringing those data sources under the same caching model as <code>fetch</code>, giving you equivalent control over revalidation without changing your data-fetching layer.</p>
<p><strong>Where should context providers be placed in the App Router, and why can't they go directly in a Server Component?</strong></p>
<p>Context providers rely on <code>createContext</code> and React's runtime context API, which are <strong>client-only features</strong>. Server Components cannot render providers directly because they don't participate in the React component tree at runtime on the client. Placing a provider in a Server Component will throw an error. Instead, you must extract the provider into a dedicated <code>'use client'</code> wrapper component, then use that wrapper inside your layout.</p>
<pre><code class="language-javascript">// app/providers.tsx
'use client';
import { ThemeProvider } from './ThemeContext';

export function Providers({ children }: { children: React.ReactNode }) {
  return &lt;ThemeProvider&gt;{children}&lt;/ThemeProvider&gt;;
}
</code></pre>
<p><strong>Where exactly in the App Router tree should the Providers wrapper be placed?</strong></p>
<p>It belongs in the <strong>root</strong> <code>layout.tsx</code> (or the closest layout that covers all routes needing that context), wrapping <code>{children}</code>. This keeps the provider as high as needed but no higher — following the principle of placing context at the lowest common ancestor.</p>
<pre><code class="language-typescriptreact">// app/layout.tsx  (Server Component)
import { Providers } from './providers';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    &lt;html lang="en"&gt;
      &lt;body&gt;
        &lt;Providers&gt;{children}&lt;/Providers&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );
}
</code></pre>
<p><strong>What is</strong> <code>revalidatePath</code> <strong>and how does it differ from</strong> <code>revalidateTag</code><strong>?</strong></p>
<p><code>revalidatePath</code> purges the cache for a <strong>specific URL path</strong>, causing that page to be re-rendered on the next request. <code>revalidateTag</code> purges all cached data entries carrying a <strong>specific tag</strong>, regardless of which pages consume them. The core difference is: <code>revalidatePath</code> thinks in terms of <em>pages</em>, <code>revalidateTag</code> thinks in terms of <em>data</em>.</p>
<pre><code class="language-typescript">revalidatePath('/blog/my-post');   // purges the /blog/my-post page cache
revalidateTag('contentful-post-123'); // purges the data tagged across any page that uses it
</code></pre>
<p><strong>When should you use</strong> <code>revalidateTag</code> <strong>over</strong> <code>revalidatePath</code><strong>?</strong></p>
<p>Prefer <code>revalidateTag</code> when the <strong>same data appears on multiple pages</strong> — a product price shown on a listing page, a detail page, and a related items widget all need to update together. Using <code>revalidatePath</code> would require knowing and calling every affected URL manually, which is brittle and doesn't scale. <code>revalidateTag</code> lets you invalidate the data once and every page consuming it gets fresh content on next request.</p>
<p>Use <code>revalidatePath</code> when the invalidation is <strong>inherently page-scoped</strong> — e.g., a user submits a form that only affects one specific page's output, or you want to force a layout re-render that isn't tied to a tagged fetch. It's simpler and more explicit when the data-to-page relationship is 1:1.</p>
<p><strong>What is</strong> <code>revalidateTag</code> <strong>and what problem does it solve?</strong></p>
<p><code>revalidateTag</code> is a Next.js server-side function that <strong>purges all cached data associated with a specific tag on demand</strong>. Without it, cached data only refreshes on a time-based interval (<code>revalidate: 60</code>). That model is too blunt for real-world apps — if a user updates their profile, you want that data fresh immediately, not after 60 seconds. <code>revalidateTag</code> lets you invalidate precisely the right cache entries the moment the underlying data changes.</p>
<pre><code class="language-typescript">// app/actions/updateUser.ts
'use server';
import { revalidateTag } from 'next/cache';

export async function updateUser(id: string, data: UserData) {
  await db.user.update({ where: { id }, data });
  revalidateTag('users'); // purges all cache entries tagged 'users'
}
</code></pre>
<p><strong>How does it work end-to-end with</strong> <code>fetch</code> <strong>and</strong> <code>unstable_cache</code><strong>?</strong></p>
<p>Tags are assigned at the data-fetching layer and consumed by <code>revalidateTag</code> at the mutation layer:</p>
<ul>
<li><p>With <code>fetch</code>: pass <code>{ next: { tags: ['users'] } }</code> in the options.</p>
</li>
<li><p>With <code>unstable_cache</code>: pass <code>{ tags: ['users'] }</code> in the config object.</p>
</li>
</ul>
<p>When <code>revalidateTag('users')</code> is called — inside a Server Action, Route Handler, or middleware — Next.js marks every cached entry carrying that tag as stale. The next request for that data triggers a fresh fetch and re-populates the cache.</p>
<p><strong>Why did the Page Router cause 30-minute rebuilds for small Contentful changes?</strong></p>
<p>In the Page Router with static rendering (<code>getStaticProps</code>), pages are pre-built at deploy time into static HTML. Any content change in Contentful required a <strong>full</strong> <code>next build</code> to regenerate every static page — even if only one blog post title changed. While Page Router did offer ISR (<code>revalidate: N</code>), it was time-based and page-scoped, meaning you still had to wait for the interval to expire or trigger a manual redeploy. There was no efficient way to say "only rebuild the pages affected by this specific content change."</p>
<p><strong>How does the App Router with</strong> <code>revalidateTag</code> <strong>solve this?</strong></p>
<p>With the App Router, pages are Server Components that fetch and cache data at runtime — not at build time. You tag your Contentful fetches with meaningful identifiers, then configure Contentful webhooks to call a Route Handler that fires <code>revalidateTag</code> the moment a content entry is published:</p>
<pre><code class="language-typescript">// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache';
import { NextRequest } from 'next/server';

export async function POST(req: NextRequest) {
  const { contentType, entryId } = await req.json();
  revalidateTag(`contentful-\({contentType}-\){entryId}`);
  return Response.json({ revalidated: true });
}
</code></pre>
<pre><code class="language-javascript">// Contentful fetch tagged at the data layer
const post = await fetch(https://cdn.contentful.com/..., { next: { tags: [contentful-blogPost-${entryId}] } });
</code></pre>
<p>Now when a Contentful editor publishes a change, the webhook fires instantly, <code>revalidateTag</code> purges only that entry's cache, and the <strong>next visitor gets fresh content within milliseconds</strong> — no rebuild, no waiting, no CI pipeline involved.</p>
<p><strong>What happens internally the moment</strong> <code>revalidateTag</code> <strong>is called?</strong></p>
<p>When <code>revalidateTag('users')</code> is called, Next.js <strong>does not immediately delete or refetch the cached data</strong>. Instead, it writes a staleness marker against all cache entries carrying that tag in the Next.js Data Cache (an in-memory + persistent cache layer managed by the Next.js server runtime). The cached data is still physically there — it's just flagged as stale. No network requests are made, no pages are re-rendered at this point. It's a near-instant, low-cost operation.</p>
<p><strong>What happens on the next incoming request after the tag is invalidated?</strong></p>
<p>When a request comes in for a page that depends on the invalidated tag, Next.js detects the stale marker during rendering and <strong>re-executes the original data-fetching function</strong> (the <code>fetch</code> or <code>unstable_cache</code> wrapped function) to get fresh data. The result is stored back into the Data Cache with a new freshness timestamp, replacing the stale entry. The page is then re-rendered with the fresh data and the new HTML is served — and optionally written to the Full Route Cache if the route is statically cacheable. Subsequent requests hit the warm cache again until the next invalidation.</p>
<p><strong>How did static pages work in the Page Router, and what changes in the App Router?</strong></p>
<p>In the Page Router, static pages were explicitly opted into with <code>getStaticProps</code> — Next.js pre-rendered them to HTML at <strong>build time</strong> and served them as flat files. In the App Router, <strong>every Server Component is statically rendered by default</strong> — there is no <code>getStaticProps</code>. If a route has no dynamic behavior (no cookies, headers, search params, or uncached data fetches), Next.js automatically pre-renders it to static HTML at build time without any configuration. The mental model shifts from "opt in to static" to "static unless you introduce something dynamic."</p>
<p><strong>What determines whether an App Router page stays static or becomes dynamic after migration?</strong></p>
<p>Next.js inspects the route at build time and checks for dynamic signals:</p>
<table>
<thead>
<tr>
<th>Signal</th>
<th>Effect</th>
</tr>
</thead>
<tbody><tr>
<td><code>cookies()</code>, <code>headers()</code></td>
<td>Forces dynamic rendering</td>
</tr>
<tr>
<td><code>searchParams</code> prop</td>
<td>Forces dynamic rendering</td>
</tr>
<tr>
<td><code>fetch</code> with <code>no-store</code></td>
<td>Forces dynamic rendering</td>
</tr>
<tr>
<td><code>export const dynamic = 'force-dynamic'</code></td>
<td>Forces dynamic rendering</td>
</tr>
</tbody></table>
<p>If none of these are present and all fetches are cached, the route is statically rendered and written to the Full Route Cache as HTML. After migrating from Page Router, pages that previously used <code>getStaticProps</code> with no user-specific data will <strong>automatically become static</strong> in the App Router — often with zero extra configuration needed.</p>
<p><strong>What is the key behavioral difference to watch for post-migration?</strong></p>
<p>In the Page Router, <code>getStaticProps</code> pages were rebuilt only on redeploy or ISR interval. In the App Router, static pages cached in the Full Route Cache can be <strong>invalidated at runtime</strong> via <code>revalidateTag</code> or <code>revalidatePath</code> — without a redeploy. This means post-migration your static pages are no longer tied to the build pipeline, which is a significant operational improvement but also means you need to be intentional about cache invalidation strategy. A page that was "always fresh on deploy" now needs explicit revalidation logic if its data changes between deploys.</p>
<p><strong>Does the App Router with Server Components replace SSG?</strong></p>
<p>Functionally, yes — but the underlying mechanism is different. In the Page Router, SSG was an <strong>explicit pattern</strong> you opted into with <code>getStaticProps</code> + <code>getStaticPaths</code>. In the App Router, static generation is the <strong>default behavior</strong>: if a Server Component route has no dynamic signals, Next.js automatically pre-renders it to static HTML at build time and caches it in the Full Route Cache. You get the same end result — pre-built HTML served at the edge — without writing any SSG-specific APIs. The concept of SSG didn't disappear; it was absorbed into the default rendering model.</p>
<p><strong>What does the App Router give you that SSG couldn't?</strong></p>
<p>SSG was an all-or-nothing commitment at the page level — the entire page was either static or dynamic. The App Router introduces <strong>per-component granularity</strong>. A single page can have a statically rendered Server Component shell (cached) wrapping a dynamically rendered section using <code>&lt;Suspense&gt;</code>, with client-interactive islands via <code>'use client'</code>. This means you can statically cache the expensive parts (navigation, product listings) while keeping user-specific parts (cart count, personalized recommendations) dynamic — something SSG fundamentally couldn't express without client-side hydration workarounds.</p>
<p><strong>When would you still think in "SSG terms" in the App Router?</strong></p>
<p>When dealing with <strong>dynamic route segments at scale</strong> — e.g., <code>/blog/[slug]</code> with thousands of posts. App Router still supports <code>generateStaticParams</code> (the successor to <code>getStaticPaths</code>) to pre-render known paths at build time. Without it, those pages render on first request and get cached afterward, meaning the very first visitor to a new URL pays the render cost. For high-traffic or SEO-critical pages, pre-generating them at build time via <code>generateStaticParams</code> is still the right call — so SSG as a <em>strategy</em> remains relevant even if SSG as an <em>API</em> is gone.</p>
<p><strong>Do Client Components appear in the initial HTML on first load in the App Router?</strong></p>
<p>Yes — and this is a common misconception. Despite being called "Client Components," they are <strong>still server-rendered to HTML on the first request</strong>. Next.js renders the entire component tree (both Server and Client Components) to HTML on the server for the initial page load, so the user sees meaningful content immediately without waiting for JavaScript. The <code>'use client'</code> directive doesn't mean "skip server rendering" — it means "this component needs to be hydrated and made interactive on the client after the HTML arrives."</p>
<p><strong>What is the difference then between Server and Client Components in terms of the initial HTML?</strong></p>
<p>Both appear in the initial HTML, but what happens <strong>after</strong> that HTML lands in the browser is different:</p>
<ul>
<li><p><strong>Server Components</strong> — rendered to HTML on the server, never hydrated. No JavaScript is sent to the client for them. They are inert HTML.</p>
</li>
<li><p><strong>Client Components</strong> — rendered to HTML on the server (for the initial load), then their JavaScript bundle is sent to the browser and React <strong>hydrates</strong> them — attaching event listeners and restoring interactive state.</p>
</li>
</ul>
<p>The practical implication is that both contribute to First Contentful Paint, but only Client Components add to the JavaScript bundle size and hydration cost.</p>
<p><strong>What is the senior-level insight about hydration and the "use client" boundary?</strong></p>
<p>The <code>'use client'</code> boundary defines where the <strong>React component tree splits</strong> — everything below that boundary in the import tree is bundled and sent to the client for hydration. This is why keeping the boundary as deep and narrow as possible matters: a <code>'use client'</code> on a large layout component pulls its entire subtree into the client bundle, increasing JS payload and hydration time. The optimal pattern is to push interactivity to small leaf components (a button, a dropdown) while keeping data-heavy parent components as Server Components — maximizing static HTML and minimizing what React needs to hydrate.</p>
<h2>Web Performance</h2>
<p><strong>What is “Critical Rendering Path“?</strong></p>
<p>As we know, the browser needs to know exactly the minimum resources required to download before rendering to avoid presenting an obviously broken experience. On the other hand, the browser can’t let the user wait for too long to download unnecessary resources for presenting some of the content to the user. The sequence of processes that the browser takes before rendering content on the first render is called the “critical rendering path“. Since the browser can’t complete the initial rendering without those critical resources, it is known as “rendering blocking resources“. The browser absolutely needs at least three types of resources:</p>
<ul>
<li><p>The initial HTML that is received from the server to construct the actual DOM</p>
</li>
<li><p>The important CSS files are used to style the initial HTML. Otherwise, if the browser keeps proceeding without waiting for them, the user will see the weird “flash“ of unstyled elements.</p>
</li>
<li><p>The critical JavaScript files are used to construct the layout synchronously.</p>
</li>
</ul>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Can you tell me the overall process of rendering the“Critical Rendering Paths“?</mark></strong></p>
<p>The Critical Rendering Path includes the Document Object Model (DOM), the CSS Object Model (CSSOM), the render tree, and layout.</p>
<p>A request for a web page or application starts with an HTTP request, and the server sends back an HTML response. The browser then begins parsing the HTML and converts the received bytes into the DOM tree. While parsing the HTML, the browser discovers external resources such as stylesheets, scripts, and images, and starts downloading them in parallel.</p>
<p>The browser continues parsing the HTML and building the DOM until it reaches the end of the document. At the same time, CSS files are parsed to build the CSSOM. Once both the DOM and CSSOM are ready, the browser combines them to build the render tree, which contains only the visible elements and their computed styles.</p>
<p>After the render tree is created, the browser performs layout to calculate the size and position of each element. Finally, the browser paints the pixels on the screen, rendering the page that the user sees.</p>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">What are “Google Web Vitals“ and “Core Web Vitals“?</mark></strong></p>
<p>Google Web Vitals is a set of standardized performance metrics defined by Google to measure the real user experience of the website. They focus on how fast it loads, how responsive it feels, and how stable it is visually while loading.</p>
<p>Core Web Vitals are a subset of Web Vitals that Google considers the most critical for user experience and uses as ranking signals in search results. There are three metrics that can be seen as Core Web Vitals: Largest Contentful Paint, Interaction To Next Paint, and Cumulative Layout Shift.</p>
<ul>
<li><p>Largest Contentful Paint (LCP): It is used to measure how long it takes for the largest visible content element to appear</p>
</li>
<li><p>Interaction to Next Paint (INP): It is a relatively new metric that was introduced in 2023, which measures how fast the app responds to user interaction with it. Basically, how “snappy“ the interaction feels</p>
</li>
<li><p>Cumulative Layout Shift (CLS): It is used to measure unexpected layout shifts while the page is loading</p>
</li>
</ul>
<p><strong>Can you explain the “Time To First Byte (TTFB)“ Metric?</strong></p>
<p>When we open the browser and navigate to a website, the browser first sends a GET request to the server and receives an initial HTML in return. The time it takes to do that is known as the “Time To First Byte“ metric</p>
<p><strong>Can you explain the "Time To Interactive (TTI)" Metric?</strong></p>
<p>Time to Interactive is a lab metric for measuring load responsiveness. It helps identify the case when the page looks interactive but actually isn't. A fast TTI helps to ensure the page is usable with fully interactive elements. This metric was removed from Lighthouse and Core Web Vitals, but it is still useful to measure the performance of the SSR app. For example, an SSR app can lead to a scenario where a page looks interactive (links and buttons are visible on the screen), but it is not interactive because the main thread is blocked or the JavaScript controlling those elements hasn't loaded. To measure, just look at the end time of the longest task before the quiet window.</p>
<p><strong>When do the DOMContentLoaded and Load Event occur?</strong></p>
<p>DOMContentLoaded and Load are two key browser events that mark the different stages of page loading.</p>
<p>The DOMContentLoaded is fired when the HTML document has been completely parsed, and the DOM tree is built. That indicates the page structure is ready for user interaction, but it may not be fully complete yet</p>
<p>The Load Event is fired when the entire page and all its dependent resources have finished loading. That indicates the page is fully loaded and visually complete.</p>
<p><strong>What are the “First Contentful Paint (FCP)“ and “Largest Contentful Paint (LCP)“?</strong></p>
<p>First Contentful Paint is one of the most important performance metrics since it measures the perceived initial load. Basically, it is the user’s first impression of how fast your website is. Until this moment, the user has to stare at the blank screen. According to Google, FCP is ideally below 1.8 seconds before users lose interest in the website.</p>
<p>Somewhere in the FCP process is where the Largest Contentful Paint (LCP) happens. Instead of the very first element, like FCP, it represents the main content of the page, the largest text, image, or video visible in the viewport. According to Google, this number should ideally be below 2.5 seconds. More than that, users will think our website is slow.</p>
<p><strong>Tell me about the “Lighthouse“ tool?</strong></p>
<p>Lighthouse is the Google performance tool integrated in the Chrome Dev Tools and can also be run as a shell script, web interface, and a Node module. We can use a Node module to run it inside our build and detect regressions before they hit production. Those Google metrics can be measured by this tool.</p>
<p>Lighthouse only gives surface-level information and doesn’t allow for simulating different scenarios, like a slow network or low CPU. It’s just a great entry point and an awesome tool to track the performance changes over time. To dig deeper into what is happening, we need the “Performance“ panel.</p>
<p><strong>How important is CDN in improving the website’s load time?</strong></p>
<p>The primary purpose of any CDN (Content Delivery Network) is to reduce the latency and deliver content to users as soon as possible. They implement multiple strategies for this, but the two most important ones are “caching“ and “distributed servers“.</p>
<p>A CDN server will have several servers in various geographical locations. These servers are closer to the end user and are able to store those copies of static files on your website and send them to users when they request.</p>
<p><strong>How would you know the resource is getting from the browser’s cache instead of getting a new version?</strong></p>
<p>When a server receives a request for a file, it could check when the file was last modified. The browser knows because the browser sends cache validation headers like <code>If-Modified-Since</code> and <code>If-None-Match</code> allowing the server to compare versions. If the date is the same as the cached file on the browser’s side, it returns with a <code>304</code> status code with an empty body(that’s why the size is too small). This indicates to the browser that it’s safe to reuse it and there's no need to re-download it.</p>
<p><strong>Can you explain the behaviour of the Cache-Control header that servers set in the response?</strong></p>
<p>The Cache-Control header can contain multiple directives in different combinations, but the most important:</p>
<ul>
<li><p>max-age with a number controls how long the particular response is going to be stored</p>
</li>
<li><p>must-revalidate directs the browser always send the request for a refreshed version if the response is stale. The response will be stale if it lives in the cache for longer than the max-age setting.</p>
</li>
</ul>
<p>If we set the max-age=0 and must-revalidate, the browser will always check with the server and never use the cache right away. And if we set to max-age=31536000(1 year), it will tell the browser to get the content right away from the browser’s cache.</p>
<p><strong>Do modern bundlers like Vite, Rollup, and Webpack always create “immutable“ JS and CSS files?</strong></p>
<p>Well, they are not truly "immutable", of course. But those tools generate file names with a hash string that depends on the file's content. If the file's content changes, then the hash changes, and the name of the file changes. As a result, when the website is deployed, the browser will re-fetch a completely fresh copy of the file regardless of the cache settings. The cache is "busted", exactly like in the exercise before when we manually renamed the CSS file.</p>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">How does the component of those libraries, such as Next.js, Remix, Tanstack, work under the hood?</mark></strong></p>
<p>All of those modern frameworks give us a component that prevents the default link behaviour and some ways to render different pages for different routes without reloading the page itself. From regex pattern matching to folder-based routing. There is no more “traditional” page navigation, which includes asking the server for the new HTML, parsing it, and so on. Instead, the already initialized JavaScript just destroys the entire page or a part of it and then generates a new page and injects it into the old page. This part is usually invisible to us and is handled entirely by React.</p>
<p>For example:</p>
<p>Somewhere in the code, there is a Link component, inside of which there is this code:</p>
<pre><code class="language-xml">&lt;a
 onClick={(e) =&gt; { 
  e.preventDefault();
  navigate(href); 
}}&gt;
{children}
&lt;/a&gt;
</code></pre>
<p>A normal tag, where the default behavior on click is prevented - i.e., the "normal" link redirect won't happen. Instead, the navigation to the next page is triggered by JavaScript via <code>navigate(href)</code>. Which is not a "navigation to the next page" per se, actually. Inside this <code>navigate</code> function, there will be something like this:</p>
<pre><code class="language-javascript">window.history.pushState({}, '', newPath); 
dispatchEvent(new PopStateEvent('popstate', { state: {} }));
</code></pre>
<p>Where window.history.pushState will simply update the URL part of the browser, and that's it, no redirects. The <code>dispatchEvent</code> part then dispatches a JavaScript event that can be listened to via <code>addEventListener</code> .</p>
<p>Somewhere else entirely, there will be a part that listens to that event and sets the state with the pathname value:</p>
<pre><code class="language-javascript">window.addEventListener('popstate', () =&gt; { 
  setPath(window.location.pathname);
});
</code></pre>
<p>And then somewhere in the third place, there will be code that renders different pages based on that state value:</p>
<pre><code class="language-javascript">switch (path) {
  case "/login":
    return &lt;LoginPage /&gt;;
  default:
    return &lt;DashboardPage /&gt;;
}
</code></pre>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Why are no JavaScript environments so important?</mark></strong></p>
<p>The fact that real people are not the ones who can access the website. There are two other major things:</p>
<ul>
<li><p>Search engine bots (crawlers), especially Google crawlers</p>
</li>
<li><p>Various social media and messages’ preview functionality</p>
</li>
</ul>
<p>All of them work in a similar manner. First, they somehow get the URL of the website. This usually happens when users share the website through social media or when search bots mindlessly crawl through miliions websites out there.</p>
<p>Second, the bots send the request to the server and receive the response, like the browser usually does</p>
<p>Third, from the received HTML, they extract useful information like text, links, and meta tags. Based on that, they form the search index, and the page becomes “Googleable “. Social media previews grab the meta tags and build the nice preview we all have seen with the large picture, title, and sometimes a short description.</p>
<p>Many old web crawler bots have no JavaScript involved, but some of the popular search engines wait for JavaScript. However, this process means that the indexing of a website relies heavily on JavaScript and might be slow and budget-intensive. Then, it’s really important for the server to return the “proper“ HTML with all critical information on the very first request.</p>
<p><strong>Can you tell me "the cost of server pre-rendering"?</strong></p>
<p>When the server receives any requests, it reads the index.html file that the build step generated in advance, converts it to a string, and sends it back to whoever requests it. It is basically what all hoisting platforms that support SPA will do for us. To fix the "no JavaScript" problem, where the browser only receives the empty div without JavaScript enabled, we need to modify the HTML on the server now because nothing stops us from modifying that string before sending it back.</p>
<p>Adding a simple pre-rendering script, it introduces two problems in complexity:</p>
<ul>
<li><p>The first problem is where we should deploy the app now. From now on, we need a server and no longer keep the hosting cost at zero for hosting static resources.</p>
</li>
<li><p>The second problem is the performance impact of having a server. Having a server introduces several problems with latency, including an unavoidable round-trip to the server for every initial load request.</p>
</li>
</ul>
<p><strong>Can you tell me what the "Server React DOM API" is and list all its methods?</strong></p>
<p>The react-dom/server APIs let you server-side render React components to HTML. These API are only used on the top level of the React app to generate initial HTML. The framework calls them for us, and we mostly don't need to import them manually. There are three types of React server APIs:</p>
<ul>
<li><p>Server APIs for Web Streams(renderToReadableStream, resume): These methods are only available in environments with Web Streams, which includes browser, Deno, and some modern edge runtimes.</p>
</li>
<li><p>Server APIs for Node.js Streams(renderToPipeableStream, resumeToPipeableStream, preRenderToNodeStream): These methods are only available in environments with Node.js Streams.</p>
</li>
<li><p>Legacy Server API for non-streaming environments(renderToString, renderToStaticMarkup): These methods can be used in environments that don't support streams</p>
</li>
</ul>
<p><strong>Explain to me the renderToString API method?</strong></p>
<p>React calls the renderToString method to render our app to an HTML string, which can be sent with our server response. This will produce the initial non-interactive HTML output of our React components. On the client, we need to call hydrateRoot method to hydrate the server-generated response to make it interactive. renderToString method returns the string immediately; it does not support streaming content as its load. We could use other modern streaming methods as alternative solutions. For server-side rendering, they can stream content in chunks as it resolves on the server, so users can see the page being progressively filled in before the client loads. For static generation, they can wait for all content to be resolved before generating the static HTML.</p>
<p><strong>What are the differences between createRoot and hydrateRoot?</strong></p>
<p>createRoot lets us create a root to display React components inside the browser DOM node.</p>
<p>hydrateRoot lets us display React components inside the browser DOM node whose HTML content was previously generated by react-dom/server.</p>
<p>The main difference is <code>createRoot</code> will clear the existing HTML before generating the new HTML using JavaScript and inject it into the browser DOM node. On the other hand, hydration will reuse the generated HTML that is received on the Server and only attaches the event handlers. If our app is SPA, then we use createRoot. In contrast, if our app is server-rendered, createRoot is not supported, and we need to use the hydrateRoot method.</p>
<p><strong>Can SSR make LCP worse?</strong></p>
<p>Unstable, there are no silver bullets in performance. If someome tell us that SRR is a 100% increase in initial load for out SPA app, they are mistaken. In the scenario when the CPU is really fast, the networking is really slow and the browser's cache is turned on, the FCP/LCP metric in SPA seems better than SSR. That is because the browser took a long time to download the initial HTML due to the slowest network in SSR. In contrast, the size of the initial HTML in SPA is really small, while the CPU is really fast for JavaScript execution. So if your app is targeting that specific niche primarily, and our app is already SPA, trying to introduce SSR to it might make it worse.</p>
<p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">Why does implemting conditional SSR Rendering is a big mistake?</mark></strong></p>
<p>We all know that some browsers' APIs, such as window, document, .. can't be used in the server's environment. A typical way to fix it would be to use a conditional check to determine whether the window is undefined or not, and then decide which parts of the code should be executed on server or browser environment. Another way that we can put the client code inside the useEffect or useLayoutEffect is because those hooks are called after hydration happens and won't be run on the server side.</p>
<pre><code class="language-javascript">const Component = () =&gt; {
// don't render anything while in SSR mode
if (typeof window === "undefined") return null;
  // render stuff when the Client mode kicks in
return ...
}
</code></pre>
<p>The natural temptation of implementing conditional SSR rendering is not going to work in the correct way. React expects that the same HTML produced by the server code is exactly the same as the HTML produced by the client code. Implementing this way makes the content on the server is different with the content on the client, that confuse it so much and React will replace the entire content of the "root" div and repalces with the freshly generated elements. The hydration mechanism is totally destroyed, with all the downsides that come with that. Sometimes, it can just introduce really weird layout bugs due to the rehydration issue.</p>
<p>The correct way to do this is to rely on React's life cycle to "hide" the non-SSR compatible blocks.</p>
<pre><code class="language-javascript">const Component = () =&gt; {
// initially, it's not mounted
const [isMounted, setIsMounted] = useState(false);
};

const Component = () =&gt; {
// initially, it's not mounted
const [isMounted, setIsMounted] = useState(false);
useEffect(() =&gt; { 
    setIsMounted(true);
}, []); 
};
</code></pre>
<p>On first render, both client and server receive the same <code>null</code> content, so the server thinks that I can trust this DOM and the hydration mechanism won't be broken.</p>
<p><strong>Why does compressing JavaScript help to improve the web performance?</strong></p>
<p>We all know that the more large in size in JavaScript bundle, the more time users need to wait for the browser complete downloading. Having a few megabytes of JavaScript on the page just feels wrong, so the issue of the bundle size and how to reduce it dominates performance-related discussions. In real life, when sending those files to users, we often would first compress them with something like gzip and brotli to reduce the size. Most of the hoisting providers have compression enabled by default, especually we are using CDN.</p>
<p><strong>What is the JavaScript Evaluation?</strong></p>
<p>If we are profiling a web application that ships a lot of JavaScript code, we might see a long task that is labeled with Evaluate Script. Script evaluation is a necessary part of executing JavaScript code in the browser, as JavaScript is compiled just-in-time before execution. When the JavaScript is evaluated, it is first parsed for errors. If the parser doesn't find any errors, then the script is compiled into bytecode, and the continue onto the execution part. The network cost of downloading JavaScript is the only thing users need to pay for once on the first visit. After that, resources can be gotten from cache, but the cost ofthe JavaScript Evaluation process is what users need to pay for every visit.</p>
<p><strong>Which tools do you use to improve the performance of the website?</strong></p>
<p>Well, there are a few tools that I use to measure the performance of the website. In the development phase, I use the React Profiler of the React Dev Tool to check if any components render unnecessarily. It helps me to identify which components are slow and why. I use the Performance tab on Chrome Dev Tools to analyze the main thread and identify what is blocking the UI during interactions. For example, when users report janky scrolling, you might find the long-running JS tasks causing frames drop. I use the Network tab when investigating slow load times. The waterfall chart reveals API delays, building issues, and caching problems. I also use the webpack-bundler-analyzer to identify dependencies that are inflating my bundle size. And Lighthouse is my go-to for auditing the overall performance, accessibility, and SEO before pushing to production.</p>
<p><strong>Can you explain those terms, like minification and tree-shaking in the bundler?</strong></p>
<p>Minification is the simplest optimization step, but surprisingly powerful. It will help you to remove all the redundant things from your final code without affecting the execution. Things such as whitespaces, comments, long variable names, and formatting, those are don’t need on your final bundle. Your final code works exactly the same, but becomes smarter, faster to download, and faster to parse.</p>
<p>Tree-shaking is a way to let the bundler remove the dead code, unused code from your final bundle. For example, you define 5 functions, but you only use one; the 4 left are never used in your codebase. Tree-shaking will remove those 4 dead code from your final bundle, which makes the final bundle to be more smaller. Tree-shaking relies heavily on ES modules (import/export). Because ES modules are static. The bundler can analyze them at build time and see which exports are actually used.</p>
<p><strong>How do we need to use the Code Splitting technique to reduce bundle size?</strong></p>
<p>The idea behind the Code Splitting technique is that when we have to send a large 5MB file to the users, if those 5Mb are packed into a single file, downloading that file will take more than a minute. So the question is: Why don't we just split that large file into multiple chunks, then let the browser download them in parallel? It will help me reduce the download time. The hard part is that we can't just cut that file into 10 random files; that is not how JavaScript works. We need to split it into isolated, independent modules and ensure that those modules can call functions in other modules. Doing this manually would be a huge headache, but luckily, most modern bundlers can do it for us.</p>
<p><a href="https://vite.dev/guide/build.html#chunking-strategy">https://vite.dev/guide/build.html#chunking-strategy</a></p>
<p><a href="https://webpack.js.org/guides/code-splitting/">https://webpack.js.org/guides/code-splitting/</a></p>
<p><strong>How do you decide when to split a large JavaScript bundle into multiple chunks?</strong></p>
<p>Answer: I focus on Cache Stability and Resource Criticality. First, I separate vendor code from app code. Since <a>node_modules</a> change rarely, splitting them allows for long-term browser caching. For the dependency tree, if a library or feature is over 100KB, I'll extract it into its own chunk. I aim for chunks between 50KB–100KB to balance parallel download speed with compression efficiency.</p>
<p><strong>Can you explain the risk of having TOO MANY small chunks in a web application?</strong></p>
<p><strong>Answer:</strong> There are two main risks. First is the <strong>Protocol Bottleneck</strong>: On HTTP/1.1, browsers are limited to ~6 concurrent connections. Too many chunks can create a "waterfall" that delays critical CSS. Second is <strong>Compression Overhead</strong>: Algorithms like Brotli work better on larger text blocks. Breaking code into tiny chunks reduces the compression ratio, potentially increasing the total transfer size.</p>
<p><strong>What is the difference between how local development and production environments handle chunking?</strong></p>
<p><strong>Answer:</strong> The primary difference is the protocol. Local dev servers often use <strong>HTTP/1.1</strong>, while production CDNs use <strong>HTTP/2 or HTTP/3</strong>. In local testing, you might see performance regressions from many chunks due to connection limits. In production, those same chunks are requested in parallel. It is vital to verify performance in a production-like environment before final decisions.</p>
<p><strong>If you move a specific UI component into a 'components' chunk, why might it still appear in the 'index' chunk?</strong></p>
<p><strong>Answer:</strong> This happens due to how the bundler traces the dependency tree. If the <code>index</code> entry point imports that component directly (or via a shared utility not included in the chunk rule), the bundler may prioritize including it in the main bundle to avoid extra round-trips. You must ensure the <code>manualChunks</code> configuration (like in Rollup/Vite) explicitly targets the file path and that imports are structured to allow isolation.</p>
<p><strong>How does code splitting improve performance beyond just the initial download speed?</strong></p>
<p><strong>Answer:</strong> It significantly reduces <strong>JavaScript Execution and Compilation time</strong>. By splitting code, the browser can parse and compile individual chunks as they arrive, rather than waiting for a single massive file to finish downloading. This frees up the Main Thread much sooner, which improves responsiveness metrics like First Input Delay (FID) or Interaction to Next Paint (INP).</p>
<hr />
<p><strong>How would you approach a task where the production JavaScript bundle has suddenly grown by 2MB?</strong></p>
<p><strong>Answer:</strong> I would start by running a <strong>Bundle Analyzer</strong> (like <code>webpack-bundle-analyzer</code> or <code>rollup-plugin-visualizer</code>) to generate a treemap of the production build. I’d look for large "blobs" in the <a>node_modules</a> section. Once a culprit is identified, I’d trace its usage in the codebase. Often, it’s a case of someone importing an entire library (like <code>lodash</code> or <code>MUI</code>) instead of specific named exports, or a new dependency being pulled in by a sub-dependency.</p>
<p><strong>What are the performance implications of using</strong> <code>import * as UI from 'library-name'</code> <strong>?</strong></p>
<p><strong>Answer:</strong> This pattern generally prevents the bundler from performing effective <strong>Tree-Shaking</strong>. By using the namespace import (<code>*</code>), you are explicitly telling the bundler that you might need any part of that library at runtime. Even if you only use <code>UI.Button</code>, many bundlers will include the entire library in the final chunk, leading to massive "Bundle Bloat" and increased parse/compile times for the user.</p>
<p><strong>Why might a "Unified Icon Library" file (one file that exports all project icons) be a bad architectural choice?</strong></p>
<p><strong>Answer:</strong> While it provides a clean developer experience (DX) and better autocomplete, it creates a <strong>bottleneck</strong>. If that central file imports 2,000 icons from a library to re-export them, every page that needs even a single "Close" icon will end up loading all 2,000 icons. This is because the bundler sees the central file as a single dependency that requires all those icons to be present.</p>
<p><strong>If a bundle analyzer shows that a library is taking up 40% of your bundle, but you only use one function from it, what are your options?</strong></p>
<p><strong>Answer:</strong> First, I would check if the library supports <strong>Named Exports</strong> (e.g., <code>import { functionName } from 'lib'</code>) which allows for tree-shaking. If it doesn't, I’d check for "sub-path imports" (e.g., <code>import functionName from 'lib/functionName'</code>). If the library is simply not tree-shakeable, I’d evaluate if there is a lighter alternative (like <code>date-fns</code> instead of <code>moment.js</code>) or if I can implement that specific logic manually to save those several hundred KB.</p>
<p><strong>What is the "Comment-Out" strategy in bundle optimization?</strong></p>
<p><strong>Answer:</strong> It’s a quick <strong>sanity check</strong> used during the investigation process. Before committing to a complex refactor, you comment out the suspected heavy imports and rebuild the project. Even though the app won't run, the build will complete, allowing you to see exactly how much the bundle size drops. This confirms that your "investigation" is targeting the right package before you spend hours on the actual fix.</p>
<p><strong>What is Tree-Shaking, and how does it differ from traditional Dead Code Elimination?</strong></p>
<p><strong>Answer:</strong> Tree-shaking is a form of dead code elimination that relies on the <strong>static structure of ES Modules</strong> (<code>import</code> and <code>export</code>). Unlike traditional DCE, which looks at segments of code that can't be reached, tree-shaking tracks the "live" exports across the entire module graph. If a module exports a function but nothing in the dependency tree imports it, the bundler "shakes" it off the tree to keep the final bundle lean.</p>
<p><strong>Why does</strong> <code>import * as Material from '@mui/material'</code> <strong>often cause performance issues in production?</strong></p>
<p><strong>Answer:</strong> In theory, modern bundlers can tree-shake namespace imports. However, in practice, if that <code>Material</code> object is ever used as a <strong>dynamic reference</strong> (like <code>Material[componentName]</code>) or wrapped in another exported object (like <code>export const Theme = { Material }</code>), the bundler loses the ability to statically analyze which specific parts of the library are needed. To be safe, it includes the entire library, which for MUI includes hundreds of components and thousands of icons.</p>
<p><strong>Can you explain a scenario where a component is imported but still excluded from the final bundle?</strong></p>
<p><strong>Answer:</strong> Yes. If I import <code>MyDialog</code> in <code>App.tsx</code> but don't actually reference it in the JSX/return statement, or if it's inside a conditional block that the bundler determines is "dead" (like <code>if (false) { ... }</code>), the bundler will see that the component is never actually "reached." Since the branch is dead, the component and all of its unique dependencies will be omitted from the production chunk.</p>
<p><strong>How would you refactor a "Global UI Wrapper" that is causing a 5MB bundle size due to Material UI imports?</strong></p>
<p><strong>Answer:</strong> I would replace the <code>import * as Material</code> with <strong>Direct/Named Imports</strong>. Instead of mapping the entire library to a key, I would import only the specific components we use—like <code>Button</code> or <code>Snackbar</code>—and explicitly add them to the wrapper object. This restores the bundler's ability to perform static analysis, ensuring that only those two components (and their specific dependencies) are included in the vendor chunk.</p>
<p><strong>Is it possible to use the "Namespace Pattern" (e.g.,</strong> <code>&lt;UI.Button /&gt;</code><strong>) without breaking tree-shaking?</strong></p>
<p><strong>Answer:</strong> It depends on the bundler, but generally, the safest way to maintain that DX is to build the <code>UI</code> object manually using named imports. For example: <code>import { Button } from './Button'; export const UI = { Button };</code>. As long as you aren't using <code>import *</code> to grab the whole directory, the bundler can see that <code>UI.Button</code> only requires the <code>Button</code> file, and it will continue to tree-shake other unused components in that directory.</p>
<p><strong>Why can a bundler tree-shake your own code easily, but often fails to tree-shake older libraries like Lodash?</strong></p>
<p><strong>Answer:</strong> Tree-shaking requires the <strong>ESM (ES Modules)</strong> format. Our own code uses <code>import</code> and <code>export</code>, which allows the bundler to map the dependency tree statically. Older libraries often distribute code in <strong>CommonJS</strong> or <strong>UMD</strong> formats. Because these formats allow dynamic requires and exports, the bundler cannot be 100% sure that a piece of code is unused, so it includes the entire library to avoid breaking the app.</p>
<p><strong>What is "Cherry-picking" in the context of bundle optimization?</strong></p>
<p><strong>Answer:</strong> Cherry-picking is the practice of importing a specific function directly from its file path rather than the library's main entry point—for example, <code>import trim from 'lodash/trim'</code> instead of <code>import { trim } from 'lodash'</code>. This bypasses the potentially non-tree-shakeable main index file and ensures only the code for that specific utility is included in the bundle.</p>
<p><strong>If</strong> <code>npx is-esm</code> <strong>returns "No" for a package, what does that tell you about its impact on your bundle?</strong></p>
<p><strong>Answer:</strong> It tells me that the package does not provide a standard ES Module entry point. Consequently, standard named imports (<code>import { x } from 'pkg'</code>) will likely fail to tree-shake, and the entire library will be bundled. In this case, I would either look for an ESM-native alternative, search the documentation for sub-path "cherry-picking" imports, or evaluate if I can replace the functionality with native JavaScript.</p>
<p><strong>How do you decide between using a utility library (like Lodash) and writing native JavaScript code?</strong></p>
<p><strong>Answer:</strong> I look at <strong>Browser Support</strong> and <strong>Bundle Cost</strong>. If I only need simple functions like <code>trim()</code> or <code>toLowerCase()</code>, I use native JavaScript because it costs 0 bytes and is highly optimized by the browser engine. I only reach for a library if I need complex, battle-tested logic (like <code>deepClone</code> or <code>debounce</code>) that would be error-prone to write manually, and even then, I ensure I'm importing only the specific functions needed.</p>
<p><strong>What is the difference between</strong> <code>import { Star } from '@mui/icons-material'</code> <strong>and</strong> <code>import Star from '@mui/icons-material/Star'</code><strong>?</strong></p>
<p><strong>Answer:</strong> The first is a <strong>Named Import</strong> from the main index. If the library is properly configured for ESM, this <em>should</em> tree-shake. The second is a <strong>Default Import</strong> from a specific file path. The second approach is "safer"—it guarantees that only the Star icon is pulled in, regardless of how complex the library's internal tree-shaking configuration is. Many developers prefer the second one for icons because it prevents "accidental" bloat from configuration errors.</p>
<p><strong>What would you do if you found three different date-manipulation libraries in a single project’s bundle?</strong></p>
<p><strong>Answer:</strong> I would perform a <strong>Unification Audit</strong>. First, I’d use a search tool to see how many times each library is used. If a heavy library like <code>moment</code> is only used in a few places, I’d refactor those instances to use a more modern, tree-shakeable alternative like <code>date-fns</code> or native <code>Intl</code> APIs. The goal is to standardize on the single most efficient library and then uninstall the others to shrink the vendor chunk significantly.</p>
<p><strong>How do you identify why a specific package is being included in your bundle if you haven't explicitly imported it?</strong></p>
<p><strong>Answer:</strong> I would use a dependency tracing tool like <code>npm-why</code> or <code>yarn why</code>. These tools show the dependency chain. For example, if I see <code>@emotion</code> in my bundle but I only use Tailwind, <code>npm-why</code> might reveal that it’s being pulled in as a sub-dependency of <code>@mui/material</code>. To get rid of it, I’d have to either replace the parent library (MUI) or find a version that doesn't rely on that transitive dependency.</p>
<p><strong>Why did replacing one</strong> <code>@emotion</code> <strong>component with a Tailwind class not immediately remove Emotion from the bundle?</strong></p>
<p><strong>Answer:</strong> This is a classic case of <strong>Transitive Dependencies</strong>. Even if you stop using a library directly in your code, it will remain in the bundle if another library you are still using (like Material UI) depends on it. Removing a library from a bundle often requires a "recursive" cleanup of all packages that reference it.</p>
<p><strong>What is the trade-off between using a UI library like Material UI vs. a headless primitive library like Radix UI?</strong></p>
<p><strong>Answer:</strong> <strong>Bundle size vs. Development speed.</strong> Material UI comes with pre-defined styles and heavy internal dependencies (like Emotion), which can bloat the bundle to several megabytes. Radix UI provides "headless" primitives (accessible logic without styles), which are much smaller and allow you to use your own lightweight CSS-in-JS or Tailwind. In performance-critical apps, switching from MUI to Radix can often save hundreds of kilobytes.</p>
<p><strong>In a "Bundle Size Initiative," how do you prioritize which libraries to refactor first?</strong></p>
<p><strong>Answer:</strong> I use the <strong>"Impact vs. Effort"</strong> matrix. I start by looking at the Bundle Analyzer. Large, non-tree-shakeable blocks that are only used in a few places are "Low Effort, High Impact" wins. Redundant libraries (like having two different icon sets) are also top priorities. I save large-scale migrations—like moving an entire themed app away from MUI—for last, as they require significant regression testing.</p>
<h2>Others</h2>
<p><strong>How do you debug issues?</strong></p>
<p>There are a few effective strategies I used to resolve the most complex issues and help me save time and energy:</p>
<ul>
<li><p>Firstly, I try to reproduce the error consistently. We can’t fix the error when we can’t see it. Once I know how to reproduce the bug, then I will try to make it fast for able to jump straight into the problem area. After that, before digging into the problem, I will try to collect as much context as possible (confirming with the QC, checking records, logs) to make sure it’s a bug and avoid missing information.</p>
</li>
<li><p>The next part is isolating the problem. Finding bugs in a large codebase is really hard. I apply the binary search approach that divides the code into working and non-working parts by commenting out the suspicious code. Repeat that process until I find exactly the problematic area. Additionally, I usually use console.log to find issues in most cases. Besides, I also use some debugger tools like VSCode Debugger, Chrome Dev Tools, and React Developer Tools if needed.</p>
</li>
<li><p>After I found the part of the code that causes the issue, I adopted a more scientific, methodological approach instead of making random changes. I start with forming a hypothesis about the root cause, add logging and breakpoints to verify it, observe the results, fix the code based on what I learn, verify the fix, and repeat the cycle again with a new hypothesis. Finding issues and fixing them depends on how much you understand the system, the flow, and how things work under the hood. Once you have a clearly knowledege how things work, you can find the issues quickly.</p>
</li>
<li><p>When I am stuck because the bug is particularly hard, I write down what I have tried. This way helps me to prevent doing the same thing twice and expecting different results. It also makes it easier for others to help me. When I feel like my brain is being shut down after hours trying to fix a bug, but couldn’t, I will step away from my laptop to take a 15 minutes walk to refresh my mind. Sometimes, I feel like it is the fastest way to solve a bug.</p>
</li>
<li><p>AI coding tools are really powerful these days, especially if we give them the right information. The right context is the key. I mostly let AI fix bugs after I found the issue and provided the solution to AI. For some simple issues, I just let the AI do all things and only review the final code.</p>
</li>
</ul>
<h1>List of the Behaviour Questions</h1>
<p><strong>Can you tell me about yourself?</strong></p>
<p>Hi, I'm Tuan. I am a Senior Front-End Engineer with over five years of experience. I have a degree in Computer Science, which gave me a very strong foundation in programming and problem-solving.</p>
<p>Throughout my career, I have specialized in React, Next.js, and TypeScript. I care a lot about the 'fundamentals'—like making sure my code is clean, SEO-friendly, and accessible for all users.</p>
<p>In my most recent role, I worked for a large international digital consultancy. For more than four years, I was the Senior Front-End Lead for a major e-commerce platform in the Australia and New Zealand region (ANZ). I was responsible for building and designing key features that helped the business grow.</p>
<p>Something that defines me is my habit of learning. For the last five years, I have read technical articles every single day. I believe a senior engineer doesn't need to know everything, but they must know how to find the right solution quickly.</p>
<p>I also have a blog where I share what I learn. I think my blog is the best way to see how I think and solve technical problems.</p>
<p><strong>Can you tell me about your work in your recent project?</strong></p>
<p>In my last project, I spent four years contributing to the front-end development for a large e-commerce website in the ANZ region.</p>
<p>As a senior engineer, I was responsible for the most complex parts of the project. This included things like a new login flow, color discovery features, and product detail pages. I always make sure I fully understand the requirements before I start writing any code.</p>
<p>My process is simple but effective:</p>
<ul>
<li><p>First, I analyze the task. If it's complex, I discuss it with my team and the lead to make sure we have a good plan.</p>
</li>
<li><p>Second, I focus on 'Clean Code' principles. I want my code to be easy to read and easy to maintain.</p>
</li>
<li><p>Third, I always write unit tests. This helps me find bugs early and deliver high-quality work on time.</p>
</li>
</ul>
<p>Because of my impact on the project, I was promoted twice during my four years there.</p>
<p><strong>What do you do to enhance your technical knowledge apart from your project work?</strong></p>
<p>I have a very disciplined approach to learning. My first priority is always to deliver my project tasks on time and with high quality. However, I believe that staying updated is part of a senior engineer's job.</p>
<p>For over five years, I have maintained a daily habit of reading technical literature. I use tools like <code>daily.dev</code>, and I follow industry experts on <code>Medium</code> and <code>Substack</code>. This helps me stay ahead of the latest trends in the JavaScript and React ecosystem.</p>
<p>When I find a truly deep or useful article, I don't just read it—I save it into my personal knowledge base. Over time, this has built a massive library of resources that help me solve complex problems quickly.</p>
<p>To solidify my knowledge, I also run a technical blog. I believe that 'to teach is to learn twice.' Writing about advanced topics and architectural patterns helps me understand them deeply. This habit ensures that I never fall behind and that I am always ready to adopt new technologies when the project needs them.</p>
<p><strong>Tell me about a time you had a disagreement with your manager.</strong></p>
<p>In my experience as a Senior Engineer, I believe that a disagreement is actually an opportunity for collaboration. I generally have a very good relationship with my leads, but when we have different opinions on a technical solution, I follow a professional process.</p>
<p>For example, if my manager proposes a solution that I think could be more optimized, I don't just say 'no.' Instead, I prepare a clear technical proposal. I show the pros and cons of my idea compared to the original one.</p>
<p>My goal is never to 'win' the argument, but to find the best solution for the project. I believe in 'Strong Opinions, Weakly Held.' This means I will advocate for the best technical path, but once a final decision is made by the lead or the team, I fully support it and work hard to make it successful.</p>
<p>This approach has helped me maintain high technical standards while keeping a very positive and professional environment in the team.</p>
<p><strong>Tell me about a situation when you had a conflict with a teammate.</strong></p>
<p>I focus on maintaining a positive team environment, so I rarely have personal conflicts. However, I once had a technical disagreement during a code review.</p>
<p>A teammate was trying to improve performance by using <code>Math.random()</code> to generate React keys everywhere on the site. I knew this would cause major performance problems because React keys must be both 'unique and stable' for the reconciliation process to work correctly.</p>
<p>At first, he didn't realize why this was a problem. Instead of pointing out the mistake in the public group chat, I reached out to him privately. I explained how React works 'under the hood' and why stable keys are necessary. I also suggested better solutions, like using unique IDs from our data.</p>
<p>He understood the explanation, updated the Pull Request, and the task was completed successfully. By handling it privately and technically, I helped my teammate grow while keeping our professional relationship very strong.</p>
<p><strong>Tell me about a time you failed. How did you deal with this situation?</strong></p>
<p>Early in my career, I made a mistake by focusing too much on speed and not enough on quality. I wanted to prove I was fast, so I jumped straight into coding before fully understanding the requirements. I skipped unit tests and didn't confirm unclear details with the Business Analyst.</p>
<p>As a result, the feature was full of bugs and didn't meet the client's needs. This delayed the release and was a very tough lesson for me. I learned that 'being fast' is useless if the work is incorrect.</p>
<p>Since that day, I have followed a disciplined process that ensures high quality:</p>
<ul>
<li><p>First, I analyze requirements deeply and ask questions early.</p>
</li>
<li><p>Second, I break big tasks into smaller, manageable parts.</p>
</li>
<li><p>Third, I always write unit tests and perform thorough 'smoke tests' before delivery.</p>
</li>
</ul>
<p>This failure helped me become the reliable Senior Engineer I am today. I now complete my tasks on time, with a very low bug rate and high-quality code.</p>
<p><strong>Describe a time when you led a team. What was the outcome?</strong></p>
<p>While I haven't held a formal 'Team Lead' title yet, I have naturally taken on informal leadership responsibilities in my senior roles.</p>
<p>For example, I am the primary person for code reviews on my team, and I mentor junior developers to help them follow best practices. I also take the lead on technical documentation and architectural proposals for new features.</p>
<p>I am very interested in moving into a formal leadership role. I have been studying management principles from industry experts to understand how to motivate a team and manage project risks. I believe my strong technical foundation and my ability to communicate clearly make me ready for this next step in my career.</p>
<p><strong>Tell me about a time that you worked well under pressure</strong></p>
<p>I remember a critical issue that appeared right on a major release day. A navigation feature that was working perfectly in testing suddenly started 'flickering' in the production environment. This was a high-pressure situation because the client needed a fix immediately to avoid delaying the launch.</p>
<p>Even though the pressure was high, I stayed calm and followed a logical debugging process:</p>
<ul>
<li><p>First, I reproduced the bug in a local environment to understand the root cause.</p>
</li>
<li><p>Second, I used a 'divide and conquer' approach by isolation—commenting out sections of code to find the exact source of the flicker.</p>
</li>
<li><p>Third, once I found the issue, I analyzed the logic and implemented a stable fix.</p>
</li>
</ul>
<p>I was able to resolve the bug within two hours. The client was very pleased with the prompt and professional response. This experience taught me that staying calm and following a methodical process is the best way to handle high-pressure situations.</p>
<p><strong>How do you handle a situation when you don’t know the answer to a question?</strong></p>
<p><strong>Answer:</strong><br />"In my experience, especially during client demos, it's very important to handle unknown questions professionally to maintain trust. I remember a time when a client asked me about a specific technology I hadn't used before. Instead of pretending to know the answer, I stayed honest and professional. I told the client: 'That's a great question. I want to give you the most accurate information, so I need to do a quick research before I confirm the details. I will get back to you by the next meeting.' I then researched the topic and consulted with my team. At the next meeting, I provided a confident and correct answer. I believe being honest is the best way to build long-term trust with stakeholders."</p>
<p><strong>Describe a time when you received tough or critical feedback.</strong></p>
<p><strong>Answer:</strong><br />"Early in my career, my Technical Lead told me that while my delivery speed was excellent, my code quality needed more focus and I needed to be more open to teammates' opinions. At first, it was hard to hear, but I realized his feedback was a gift to help me grow. I decided to change my approach immediately by taking more time for self-reviews, performing strict 'smoke tests' before delivery, and being more open-minded during discussions. My lead was very satisfied with my improvement, and this feedback actually helped me transition into a Senior role. It taught me that a great engineer must be humble and focus on quality above all else."</p>
<p><strong>Describe a time when you had to give someone critical feedback. How did you handle it?</strong></p>
<p><strong>Answer:</strong><br />"In my senior role, I often mentor junior developers. I once worked with a talented developer who was misusing React memoization hooks like <code>useMemo</code> and <code>useCallback</code> everywhere. I arranged a private one-on-one meeting to provide constructive feedback. Instead of just highlighting the mistake, I explained how React works under the hood and why over-memoization can actually hurt performance. I also shared deep-dive resources to help him learn. He responded well, updated his code correctly, and thanked me for the guidance. For me, giving feedback is about helping the team grow together."</p>
<p><strong>Describe a time when you anticipated potential problems and developed preventive measures</strong></p>
<p><strong>Answer:</strong><br />"During a major performance refactoring phase, I noticed a significant risk in our codebase. Our team had agreed to refactor React keys to improve rendering, but a teammate incorrectly implemented a utility using <code>Math.random()</code> to generate keys globally. I recognized immediately that this would cause React to re-mount every component on every render, leading to a performance disaster. I rejected the Pull Request and organized a meeting to explain the reconciliation process and why keys must be both unique and stable. By catching this early and mentoring my teammate on React internals, I prevented a critical production issue and helped the team adopt a more robust implementation strategy."</p>
<p><strong>Describe a situation when you had to deal with a difficult customer</strong></p>
<p><strong>Answer:</strong><br />"In my role as a Senior Engineer, I primarily interface with project stakeholders and onsite partners rather than direct retail customers. I’ve found that the best way to prevent 'difficult' situations with any stakeholder is through consistent transparency and high-quality delivery. For example, by providing clear technical demos during bi-weekly standups and maintaining open communication on JIRA, I’ve built a high level of trust with our international partners. Because our team consistently hits milestones and maintains a low bug rate, my interactions with stakeholders have remained very positive and collaborative."</p>
<p><strong>Tell me a time when you missed a deadline. What happened, and how did you handle it?</strong></p>
<p><strong>Answer:</strong><br />"I am very disciplined with planning, so I rarely miss deadlines. However, I once encountered a situation where a critical requirement was missing from a ticket late in the sprint. Instead of rushing to code a partial solution, I immediately raised the risk to my Project Manager and Business Analyst. I worked closely with them to clarify the missing logic and provided a new, realistic estimate for the update. Even though the original internal target shifted, I committed to a new delivery time and worked diligently—including extra hours—to ensure the final feature was shipped with zero bugs for the main release. This taught me that early communication is the most important tool when facing a deadline risk."</p>
<p><strong>Describe when your workload was heavy and how you handled it</strong></p>
<p><strong>Answer:</strong><br />"During the implementation of a new authentication flow using Azure B2C, my workload suddenly doubled when my Lead was pulled into another urgent release. I was assigned the entire authentication UI suite—including login, sign-up, and password recovery—with a very tight deadline. These tasks required a deep dive into native HTML, CSS, and JavaScript within a complex specialized platform. I handled this by first performing a risk assessment and communicating the new effort requirements to my PM. Once the stakeholders were aligned, I focused on a methodical execution. I successfully shipped all forms on time, receiving high praise from the client for delivering a complex feature smoothly under pressure."</p>
<p><strong>Describe a time you had to deal with a significant change at work. How did you adapt?</strong></p>
<p><strong>Answer:</strong><br />"In my experience, significant changes are best handled through a structured technical investigation. While our project requirements are usually well-defined, I am always prepared for shifts in scope. If a major change occurs, my first step is to perform a deep-dive analysis into the existing codebase to identify similar patterns. I then research the official documentation and best practices for the new requirements. Before starting any implementation, I break the solution down into technical tasks with realistic estimations. I then proactively communicate the impact and the timeline to my Project Manager and Business Analyst. This structured approach ensures that the change is integrated smoothly without risking the stability of the overall release."</p>
<p><strong>Describe a situation where you saw a problem and took an initiative to correct it</strong></p>
<p><strong>Answer:</strong><br />"While working on a new feature, I noticed a critical bug in a common utility function that was being used across the entire site. A teammate had implemented an asynchronous operation inside a <code>forEach</code> loop, which was causing intermittent race conditions and mysterious bugs. Even though this wasn't part of my assigned ticket, I took the initiative to address it. I reached out to my teammate privately and explained why <code>forEach</code> doesn't wait for promises and how to correctly use <code>for...of</code> or <code>Promise.all</code>. I helped him refactor the utility and verify the fix. By taking this initiative, I not only fixed a major hidden bug but also shared important technical knowledge with the team."</p>
<p><strong>Describe a time when there was a conflict with your team. How did you help resolve it?</strong></p>
<p><strong>Answer:</strong><br />"Early in my career, I was sometimes too protective of my own technical choices, which occasionally led to friction during code reviews. I realized that being a great engineer isn't just about writing code; it's about collaboration. I made a conscious decision to change my mindset. Now, I view every comment as an opportunity to improve the project. When a conflict arises, I stay calm, take a breath, and evaluate the feedback objectively. If I disagree with a bug report or a review comment, I don't argue; instead, I arrange a quick call to explain my logic clearly. If we still don't agree, I involve a third party like a Tech Lead or BA to provide a neutral perspective. This transition from being 'stubborn' to being 'collaborative' has significantly boosted my productivity and strengthened my relationship with my team."</p>
<p><strong>Describe a time when you went out of your comfort zone. What lessons did you learn?</strong></p>
<p><strong>Answer:</strong><br />"The most significant time I stepped out of my comfort zone was when I moved from a local project to an international one with English-speaking clients in the ANZ region. Initially, I was very nervous about demoing my features in English during bi-weekly standups. I even tried to avoid them at first. However, I soon realized that to grow as a Senior Engineer, I needed to master technical communication. I started preparing for my demos much more thoroughly—writing scripts and practicing my speaking. I stopped hiding and began actively presenting my weekly achievements. This experience taught me that growth happens when you face your fears. My confidence improved, my PM noticed a huge difference, and I am now very comfortable presenting complex technical flows to international stakeholders."</p>
<p><strong>Describe a time when you took a big risk, and it failed</strong></p>
<p><strong>Answer:</strong><br />"I am generally a risk-averse engineer who prefers careful planning, but there was a situation where I had to step up during an emergency. A teammate went on leave right before a production release, leaving a complex GraphQL change unfinished. Even though I am primarily a Front-End expert, I volunteered to handle the backend integration. I worked extra hours to learn the new GraphQL patterns and coordinated across teams to meet the deadline. In the end, I only completed about 80% of the task on my own and needed a lead's help for the final integration. While I didn't finish everything 100% independently, it was a valuable experience. I learned how to manage high-pressure cross-stack tasks, and the client was very impressed with my willingness to take on a difficult challenge to ensure the release was a success."</p>
<p><strong>Describe a time you had to explain a complex technical concept to someone non-technical</strong></p>
<p><strong>Answer:</strong><br />"Early in my career, I struggled to explain technical details to non-developers like BAs or QCs. I eventually realized that effective communication is a core senior skill. My approach changed from focusing on <em>how</em> a feature works to <em>why</em> it matters for the business. Now, when I explain a technical concept, I use analogies and focus on the user impact rather than the implementation detail. For example, instead of discussing 'asynchronous state synchronization,' I talk about how the system ensures the user's data remains consistent across the whole site. This shift in perspective has made my collaborations with the QA and Product teams much smoother and more productive."</p>
<p><strong>Tell me a time you disagreed with your colleague. How did you handle this situation?</strong></p>
<p><strong>Answer:</strong><br />"I believe that healthy technical debate is essential for a high-quality project. When I have a disagreement with a colleague, I focus on staying objective and professional. I avoid personal tension and instead move the discussion to a dedicated technical meeting where we can look at the facts. During these sessions, I practice active listening to understand their reasoning before sharing my own perspective. If we reach a stalemate, I proactively involve our Technical Lead to provide a neutral 'third party' decision. My priority is always the best interest of the project, not 'winning' the argument. This approach ensures that we remain effective teammates even after a tough technical decision."</p>
<p><strong>Tell me about a complex task you have worked on recently</strong></p>
<p><strong>Answer:</strong><br />"Recently, I led the front-end implementation for a major authentication migration to Azure B2C. This was a high-stakes project delivered at the end of the year. The challenge was that I had to build a modern, high-fidelity UI using native HTML, CSS, and JavaScript, as the platform did not support modern frameworks like React. The documentation was also quite limited. I handled this by performing deep-dive research into the Azure B2C Custom Policy framework and breaking the large project into modular vanilla JavaScript classes. Despite the technical constraints and tight deadlines, I delivered the full suite of Login, Sign-up, and Password Recovery flows on time with zero critical bugs. It was a great example of using core web fundamentals to solve a complex architectural problem."</p>
<p><strong>How do you stay up-to-date with the latest technological advancements?</strong></p>
<p><strong>Answer:</strong><br />"I view continuous learning as a daily discipline rather than an occasional task. For over five years, I have dedicated at least two hours a day to staying updated with the JavaScript and React ecosystem. I rely on a curated library of resources, including <a href="http://daily.dev">daily.dev</a>, Medium, and various expert newsletters. To ensure my knowledge is practical and stays with me, I maintain a technical blog where I document advanced concepts and 'lessons learned' from my projects. I believe a senior engineer's value comes from their ability to bring these new, optimized solutions into their team's workflow to prevent the project from falling behind technologically."</p>
<p><strong>Give me an example of a time you had to debug a challenging technical issue.</strong></p>
<p><strong>Answer:</strong><br />"I recently handled a challenging cross-device issue where a production bug only appeared on mobile Safari. Because our environment was behind a strict VPN, I couldn't use standard remote debugging tools easily. To solve this, I followed a methodical 'isolation' process. I first verified the requirement to ensure it wasn't a misunderstanding, then I used logging and targeted code removal to 'scope down' the bug locally. Once I identified the root cause—a specific CSS legacy behavior in Safari—I coordinated with the team to implement a stable fix that wouldn't impact other browsers. I find that a calm, step-by-step reproduction process is the most effective way to resolve even the most difficult technical issues."</p>
<h1>References</h1>
<p><a href="https://github.com/ashishps1/awesome-behavioral-interviews">https://github.com/ashishps1/awesome-behavioral-interviews</a></p>
<p><a href="https://javascript.plainenglish.io/93-of-frontend-developers-cant-explain-react-profiler-vs-lighthouse-here-s-what-actually-2bdf07b0f253">https://javascript.plainenglish.io/93-of-frontend-developers-cant-explain-react-profiler-vs-lighthouse-here-s-what-actually-2bdf07b0f253</a></p>
<p><a href="https://javascript.plainenglish.io/the-one-frontend-interview-question-that-humbled-me-after-100-interviews-42935d92496c">https://javascript.plainenglish.io/the-one-frontend-interview-question-that-humbled-me-after-100-interviews-42935d92496c</a></p>
<p><a href="https://medium.com/@jaganjvvn/real-world-frontend-interview-answers-javascript-react-typescript-b531f8298a8f">https://medium.com/@jaganjvvn/real-world-frontend-interview-answers-javascript-react-typescript-b531f8298a8f</a></p>
<p><a href="https://javascript.plainenglish.io/15-react-interview-questions-every-mid-level-developer-should-be-ready-for-in-2025-38ee70bc114c">https://javascript.plainenglish.io/15-react-interview-questions-every-mid-level-developer-should-be-ready-for-in-2025-38ee70bc114c</a></p>
<p><a href="https://javascript.plainenglish.io/mastering-the-senior-react-developer-interview-real-world-questions-you-must-prepare-for-46cda3df1c82">https://javascript.plainenglish.io/mastering-the-senior-react-developer-interview-real-world-questions-you-must-prepare-for-46cda3df1c82</a></p>
<p><a href="https://www.developerway.com/posts/server-actions-for-data-fetching">https://www.developerway.com/posts/server-actions-for-data-fetching</a></p>
<p><a href="https://javascript.plainenglish.io/mastering-the-senior-react-developer-interview-real-world-questions-you-must-prepare-for-46cda3df1c82">https://javascript.plainenglish.io/mastering-the-senior-react-developer-interview-real-world-questions-you-must-prepare-for-46cda3df1c82</a></p>
<p><a href="https://thetshaped.dev/p/conscious-debugging-10-effective-debugging-strategies-debug-like-pro">https://thetshaped.dev/p/conscious-debugging-10-effective-debugging-strategies-debug-like-pro</a></p>
<p><a href="https://www.developerway.com/posts/debugging-with-ai">https://www.developerway.com/posts/debugging-with-ai</a></p>
<p><a href="https://medium.com/@kanishks772/every-bug-i-ever-fixed-made-sense-only-after-i-understood-these-7-layers-ebcae423399b">https://medium.com/@kanishks772/every-bug-i-ever-fixed-made-sense-only-after-i-understood-these-7-layers-ebcae423399b</a></p>
]]></content:encoded></item><item><title><![CDATA[All The New Features In Next.js]]></title><description><![CDATA[Next 16
Next.js 16.0.1 is live, and it is not just a point release. It tightens the App Router story, clarifies caching with Cache Components, promotes Turbopack to the default, and ships practical breaking changes that you should address before merg...]]></description><link>https://blog.tuanhadev.tech/all-the-new-features-in-nextjs</link><guid isPermaLink="true">https://blog.tuanhadev.tech/all-the-new-features-in-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Next.js 15]]></category><category><![CDATA[#next14]]></category><category><![CDATA[Next.js 13.2]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Sun, 03 Aug 2025 11:14:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/oqStl2L5oxI/upload/1ad12b6260d06a66616e35c73b46a883.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-next-16">Next 16</h1>
<p>Next.js 16.0.1 is live, and it is not just a point release. It tightens the App Router story, clarifies caching with Cache Components, promotes Turbopack to the default, and ships practical breaking changes that you should address before merging that upgrade pull request. The official docs header shows 16.0.1 as the latest version, so let’s treat this as the new baseline.</p>
<h2 id="heading-cache-components-the-star-of-nextjs-16">Cache Components — The Star of Next.js 16</h2>
<p>One of the most significant changes is the introduction of <strong>Cache Components</strong>, a new opt-in caching model powered by the <code>'use cache'</code> directive.</p>
<p>It’s built on top of the <strong>Partial Pre-Rendering (PPR)</strong> work started in 2023 — but now, it’s simpler and more powerful.</p>
<p>Instead of implicit caching rules, developers can now explicitly define what gets cached and what executes dynamically at runtime.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// next.config.ts</span>
<span class="hljs-keyword">const</span> nextConfig = {
  <span class="hljs-attr">cacheComponents</span>: <span class="hljs-literal">true</span>,
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> nextConfig;
</code></pre>
<p>💡 <strong>Why it matters:</strong><br />Before, you had to choose between fully static or fully dynamic rendering.<br />Now, with Cache Components, you can <strong>mix both</strong> — static shells with dynamic data chunks.<br />This gives you the <em>speed of SSG</em> with the <em>freshness of SSR</em>, all within a unified architecture.</p>
<h2 id="heading-turbopack-now-the-default-bundler">Turbopack — Now the Default Bundler</h2>
<p>After nearly two years of testing, <strong>Turbopack</strong> is finally stable and is now the <strong>default bundler</strong> for all new Next.js projects.</p>
<p>Built in Rust, Turbopack delivers jaw-dropping performance gains:</p>
<ul>
<li><p>🚀 <strong>2–5× faster</strong> production builds</p>
</li>
<li><p>🔁 <strong>Up to 10× faster</strong> Fast Refresh during local development</p>
</li>
</ul>
<p>You can still fall back to Webpack if you need to:</p>
<pre><code class="lang-javascript">next dev --webpack
next build --webpack
</code></pre>
<p>💡 <strong>Why it matters:</strong><br />Shorter feedback loops mean faster iteration, smaller CI/CD times, and a smoother dev experience — especially for teams working on massive codebases or micro-frontends.</p>
<h2 id="heading-nextjs-devtools-mcp-ai-assisted-debugging">Next.js DevTools MCP — AI-Assisted Debugging</h2>
<p>This release debuts <strong>Next.js DevTools MCP (Model Context Protocol)</strong> — bringing AI-powered insights right into your dev workflow.</p>
<p><strong>What it does:</strong></p>
<ul>
<li><p>Understands your app’s routing, caching, and rendering logic</p>
</li>
<li><p>Combines browser + server logs into one view</p>
</li>
<li><p>Let’s AI agents (like Codex or Copilot) explain, debug, and suggest fixes contextually</p>
</li>
</ul>
<p>💡 <strong>Why it matters:</strong><br />This bridges the gap between AI assistance and real-world debugging.<br />You can finally ask <em>“why is this route slow?”</em> and get contextual answers — not just generic suggestions.</p>
<h2 id="heading-proxyts-replacing-middlewarets">proxy.ts — Replacing middleware.ts</h2>
<p><code>middleware.ts</code> has officially been replaced by <code>proxy.ts</code> to make your <strong>network boundary explicit</strong>.</p>
<p>This runs only on the Node.js runtime and provides clearer semantics for request interception.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// proxy.ts</span>
<span class="hljs-keyword">import</span> { NextRequest, NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">proxy</span>(<span class="hljs-params">request: NextRequest</span>) </span>{
  <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/home'</span>, request.url));
}
</code></pre>
<p>💡 <strong>Why it matters:</strong><br />It simplifies your app’s network layer and prevents confusion about where middleware logic runs.<br />If you were previously using middleware for redirects or auth, simply rename your file and function — you’re done.</p>
<h2 id="heading-enhanced-routing-and-navigation">Enhanced Routing and Navigation</h2>
<p>Next.js 16 completely re-engineers routing and navigation for <strong>leaner page transitions</strong>.</p>
<p><strong>Key highlights:</strong></p>
<ul>
<li><p><strong>Layout Deduplication:</strong> Shared layouts load once, even when prefetching multiple URLs.</p>
</li>
<li><p><strong>Incremental Prefetching:</strong> Only fetches parts not already cached.</p>
</li>
<li><p><strong>Smart Re-Prefetching:</strong> Automatically re-fetches invalidated data when links re-enter the viewport.</p>
</li>
</ul>
<p>💡 <strong>Why it matters:</strong><br />Large apps (think dashboards, analytics, HR portals) benefit massively — lower transfer sizes, faster navigation, and near-instant reloads between sections.</p>
<h2 id="heading-new-and-improved-caching-apis">New and Improved Caching APIs</h2>
<p>Next.js 16 refines how developers manage cache invalidation and freshness.</p>
<p><strong>✅</strong> <code>revalidateTag()</code> <strong>(Updated)</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { revalidateTag } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/cache'</span>;
<span class="hljs-comment">// Using built-in cacheLife profile</span>
revalidateTag(<span class="hljs-string">'blog-posts'</span>, <span class="hljs-string">'max'</span>);
<span class="hljs-comment">// Custom revalidation</span>
revalidateTag(<span class="hljs-string">'products'</span>, { <span class="hljs-attr">revalidate</span>: <span class="hljs-number">3600</span> });
</code></pre>
<p><strong>🆕</strong> <code>updateTag()</code> <strong>(New)</strong></p>
<p>For immediate “read-your-writes” consistency inside Server Actions:</p>
<pre><code class="lang-javascript"><span class="hljs-string">'use server'</span>;
<span class="hljs-keyword">import</span> { updateTag } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/cache'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateUserProfile</span>(<span class="hljs-params">userId, profile</span>) </span>{
  <span class="hljs-keyword">await</span> db.users.update(userId, profile);
  updateTag(<span class="hljs-string">`user-<span class="hljs-subst">${userId}</span>`</span>);
}
</code></pre>
<p><strong>🆕</strong> <code>refresh()</code> <strong>(New)</strong></p>
<p>For refreshing <strong>uncached</strong> data without touching cached content.</p>
<p>💡 <strong>Why it matters:</strong><br />You now have <strong>total control</strong> over cache lifecycle — perfect for user dashboards, analytics panels, or anything requiring instant feedback after an update.</p>
<h2 id="heading-react-192-support-and-compiler-integration">React 19.2 Support and Compiler Integration</h2>
<p>Next.js 16 ships with <strong>React 19.2</strong> and full support for the <strong>React Compiler</strong> (automatic memoization).</p>
<p>Highlights include:</p>
<ul>
<li><p><strong>View Transitions</strong> for smooth animations between pages</p>
</li>
<li><p><strong>useEffectEvent()</strong> for better effect logic isolation</p>
</li>
<li><p>for managing background UI states</p>
</li>
</ul>
<p>To enable the compiler:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> nextConfig = {
  <span class="hljs-attr">reactCompiler</span>: <span class="hljs-literal">true</span>,
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> nextConfig;
</code></pre>
<p>And install the plugin:</p>
<pre><code class="lang-javascript">npm install babel-plugin-react-compiler@latest
</code></pre>
<p>💡 <strong>Why it matters:</strong><br />Automatic memoization means fewer unnecessary re-renders and smoother UIs — no manual <code>useMemo</code> or <code>useCallback</code> needed.</p>
<h1 id="heading-nextjs-15">Next.js 15</h1>
<p>Next.js 15 Release Candidate (RC) introduces a range of new features &amp; improvements aimed at enhancing the development experience and performance of web applications. This release builds on the strengths of the previous version while at the same time introducing innovative capabilities that promise to streamline workflows and optimize application performance. Below is a detailed overview of the key updates in Next.js 15 RC.</p>
<h2 id="heading-create-react-app-upgrades-cleaner-ui-700x-faster-build"><code>create-react-app</code> upgrades: cleaner UI, 700x faster build</h2>
<h3 id="heading-reformed-design">Reformed design</h3>
<p>❌From this:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*sqGiF6xuMoGScfwK.png" alt /></p>
<p>✅To this:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*Ll6wKZ5z89-u-NXp.png" alt /></p>
<h3 id="heading-webpack-turbopack">Webpack → Turbopack</h3>
<p>Turbopack: The fastest module builder in the world.</p>
<ul>
<li><p>700x faster than Webpack</p>
</li>
<li><p>10x faster than Vite</p>
</li>
</ul>
<p>And now with v15, adding it to your Next.js project is easier than ever before:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*VDKnZqX05FOmlZe-.png" alt /></p>
<h2 id="heading-typescript-configs-nextconfigts">Typescript configs - next.config.ts</h2>
<p>With Next.js 15, you can finally create the config file in TypeScript directly.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*TVWF6KRv0KhwVeS0OjSWIQ.png" alt /></p>
<p>The NextConfig type enables editor IntelliSense for every possible option.</p>
<h2 id="heading-react-compiler-react-19-support-and-user-friendly-errors">React Compiler, React 19 Support, and User-Friendly Errors</h2>
<h3 id="heading-react-compiler">React Compiler</h3>
<p>React Compiler is a React Compiler (who would have thought)</p>
<p>A modern compiler that understands your React code at a deep level</p>
<p>Bringing optimizations like automatic memoization, destroying the need for useCallback and useMemo in the vast majority of cases.</p>
<p>Saving time, preventing errors, and speeding things up.</p>
<p>And it’s really easy to set up: You just install <code>babel-plugin-react-compiler</code>:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*irPPTpcHY7sqt5coyENX2g.png" alt /></p>
<p>And add this to <code>next.config.js</code></p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*hnxIzGvuifsLwCtJ8aG9_Q.png" alt /></p>
<h3 id="heading-react-server-actions-stable-with-react-19">React Server Actions (Stable with React 19)</h3>
<p><strong>Say goodbye to complex API routes.</strong></p>
<p>Next.js 15 supports React Server Actions, allowing you to handle server logic directly inside your component files.</p>
<p>You declare them using a special <code>"use server"</code> directive.</p>
<pre><code class="lang-typescript"><span class="hljs-string">"use server"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">submitContactForm</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-keyword">await</span> db.contact.insert(data);
}
</code></pre>
<p>Then call them from a <code>&lt;form&gt;</code>:</p>
<pre><code class="lang-typescript">&lt;form action={submitContactForm}&gt;
  &lt;input name=<span class="hljs-string">"email"</span> /&gt;
  &lt;textarea name=<span class="hljs-string">"message"</span> /&gt;
  &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Send&lt;/button&gt;
&lt;/form&gt;
</code></pre>
<p><strong>✅ Benefits:</strong></p>
<ul>
<li><p>Eliminates boilerplate API files</p>
</li>
<li><p>Fully type-safe and colocated</p>
</li>
<li><p>Keeps data handling strictly server-side</p>
</li>
<li><p>No need for fetch(), Axios, or client mutation libraries</p>
</li>
</ul>
<blockquote>
<p><em>💡 Server Actions unlock a more intuitive, secure, and maintainable full-stack pattern.</em></p>
</blockquote>
<h3 id="heading-react-server-components-rsc-less-javascript-more-speed">React Server Components (RSC): Less JavaScript, More Speed</h3>
<p>React Server Components allow you to fetch data and render UI on the server without sending any unnecessary JavaScript code to the client. They are server-only by default, which improves performance dramatically:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Server Component (default in `app/`)</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> fetchProducts();
  <span class="hljs-keyword">return</span> &lt;ul&gt;{products.map(<span class="hljs-function"><span class="hljs-params">p</span> =&gt;</span> &lt;li key={p.id}&gt;{p.name}&lt;<span class="hljs-regexp">/li&gt;)}&lt;/u</span>l&gt;;
}
</code></pre>
<p><strong>✅ Benefits:</strong></p>
<ul>
<li><p>30–50% smaller JS bundles</p>
</li>
<li><p>No hydration costs</p>
</li>
<li><p>Co-locates data fetching with UI</p>
</li>
<li><p>Boosts Core Web Vitals (LCP, FID, etc.)</p>
</li>
</ul>
<blockquote>
<p><em>RSCs make your apps faster, more secure, and easier to scale.</em></p>
</blockquote>
<h3 id="heading-better-hydration-errors">Better hydration errors</h3>
<p>Dev quality of life means a lot, and error messages’ usefulness plays a big part in that.</p>
<p>Next.js sets the bar higher: now making intelligent suggestions on possible ways to fix the error:</p>
<p>Before v15:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*CBCVhMZhDZhgys9K.png" alt /></p>
<p>Now:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*JagK0wYU3dKSnN2Z.png" alt /></p>
<p>You know I have had a tough time in the past from these hydration errors, so this will certainly be an invaluable one for me.</p>
<h2 id="heading-new-caching-behavior">New Caching Behavior</h2>
<p>No more automatic caching</p>
<p>For all:</p>
<ul>
<li><p><code>fetch()</code> requests</p>
</li>
<li><p>Route handlers: <code>GET</code>, <code>POST</code>, etc.</p>
</li>
<li><p><code>&lt;Link&gt;</code> client-side navigation.</p>
</li>
</ul>
<p>This change ensures that the data served is always fresh, reducing the chances of displaying outdated information to users. Next.js development company now has more control over caching behaviors, allowing for more precise optimization of application performance.</p>
<p>But if you still want to cache <code>fetch()</code>:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*B7XJWo-AxawNa0IW_XDtSQ.png" alt /></p>
<p>Then you can cache the others with some <code>next.config.js</code> options.</p>
<h2 id="heading-partial-prerendering-ppr">Partial Prerendering (PPR)</h2>
<p>PPR combines static and dynamic rendering on the same page</p>
<p>With PPR, you can wrap dynamic UI components in a Suspend boundary and opt in specific Layouts and Pages for partial prerendering. When a request comes in, Next.js will immediately serve a static HTML shell and then render and stream the dynamic parts in the same HTTP request.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*TWBn9ld6UHEhSZk3zVLGwg.png" alt /></p>
<p>All you need is this in <code>next.config.js</code>:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*7iAoXL87zAkSbCqdJ7VghQ.png" alt /></p>
<h2 id="heading-after">after</h2>
<p>Next.js 15 gives you a clean way to separate essential from non-essential tasks from every server request:</p>
<ul>
<li><p>Essential: Auth checks, DB updates, etc.</p>
</li>
<li><p>Non-essential: Logging, analytics, etc.</p>
</li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*EmtIJQQXUjJX48FtSmfZqQ.png" alt /></p>
<p>Start using it now with <code>experimental.after</code>:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*-dKgxzM65A_hDs3DlFishA.png" alt /></p>
<h2 id="heading-stable-app-router-with-layouts-and-nested-routing">Stable App Router with Layouts and Nested Routing</h2>
<p>Introduced in v13 and now fully stable, the /app directory in Next.js 15 gives you modular routing with nested layouts, co-located data fetching, and component-based architecture.</p>
<p><strong>📁 Folder structure:</strong></p>
<pre><code class="lang-typescript">app/
  layout.tsx
  page.tsx
  dashboard/
    layout.tsx
    page.tsx
</code></pre>
<p><strong>🎯 Why it matters:</strong></p>
<ul>
<li><p>Improved scalability for large apps</p>
</li>
<li><p>Built-in support for error boundaries and loading states</p>
</li>
<li><p>Cleaner structure that mirrors component trees</p>
</li>
</ul>
<p><strong>Ideal for</strong>: scalable dashboard, admin panels, and modular websites.</p>
<h2 id="heading-smarter-ltimage-gt-component">Smarter &lt;Image /&gt; Component</h2>
<p>The <code>&lt;Image /&gt;</code> component in Next.js 15 is now:</p>
<ul>
<li><p>Faster</p>
</li>
<li><p>Lighter</p>
</li>
<li><p>Easier to use</p>
</li>
</ul>
<p><strong>Enhancements:</strong></p>
<ul>
<li><p>Native <code>loading="lazy"</code></p>
</li>
<li><p>Blur/SVG placeholders</p>
</li>
<li><p>Better AVIF/WebP support</p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;Image
  src=<span class="hljs-string">"/banner.jpg"</span>
  alt=<span class="hljs-string">"Banner"</span>
  width={<span class="hljs-number">800</span>}
  height={<span class="hljs-number">400</span>}
  placeholder=<span class="hljs-string">"blur"</span>
/&gt;
</code></pre>
<p><strong>✅ Benefits:</strong></p>
<ul>
<li><p>Improves LCP and CLS</p>
</li>
<li><p>No need for 3rd-party CDNs</p>
</li>
<li><p>Works out of the box</p>
</li>
</ul>
<h2 id="heading-edge-middleware-fast-personalized-routing">Edge Middleware: Fast, Personalized Routing</h2>
<p>Edge Middleware runs <strong>before</strong> a page is rendered and allows you to:</p>
<ul>
<li><p>Redirect by location or cookies</p>
</li>
<li><p>Block bots</p>
</li>
<li><p>Inject A/B testing logic</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">// middleware.ts</span>
<span class="hljs-keyword">import</span> { NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">req</span>) </span>{
  <span class="hljs-keyword">const</span> country = req.geo?.country;
  <span class="hljs-keyword">if</span> (country === <span class="hljs-string">'FR'</span>) {
    <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/fr'</span>, req.url));
  }
  <span class="hljs-keyword">return</span> NextResponse.next();
}
</code></pre>
<p><strong>✅ Benefits:</strong></p>
<ul>
<li><p>Personalization without latency</p>
</li>
<li><p>Logic at the CDN edge</p>
</li>
<li><p>Great for internationalization and auth flows</p>
</li>
</ul>
<h2 id="heading-uselinkstatus">useLinkStatus</h2>
<p>The <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/use-link-status">useLinkStatus hook</a> was introduced in Next.js v15.3.0. It tracks the pending state in the Next.js Link component.</p>
<p>You can use it to provide inline visual feedback to the user, such as displaying spinners or text effects, while navigating to the new route.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754209661925/6ee21c4e-c99c-42e2-87db-23206e78f78d.gif" alt class="image--center mx-auto" /></p>
<p><strong>Key Features:</strong></p>
<ul>
<li><p>You can only use the useLinkStatus hook inside the Next.js Link Component.</p>
</li>
<li><p>Make sure to set the <code>prefetch={false}</code> in the Next.js Link component to use the useLinkStatus hook in your project.</p>
</li>
<li><p><code>useLinkStatus</code> hook is used to show the loading state during the navigation transitions.</p>
</li>
<li><p>The useLinkStatus must be used within a descendant of a Link component.</p>
</li>
<li><p>The useLinkStatus hook returns a pending boolean value</p>
</li>
<li><p>The useLinkStatus helps improve the user experience on slow networks</p>
</li>
</ul>
<p><strong>We use the useLinkStatus hook for:</strong></p>
<ul>
<li><p>The useLinkStatus hook is useful when prefetching (prefetch=false) is disabled in the Next.js Link component.</p>
</li>
<li><p>With the useLinkStatus hook, you want to show inline visual feedback during navigation</p>
</li>
</ul>
<h3 id="heading-how-does-the-uselinkstatus-hook-work">How does the useLinkStatus hook work?</h3>
<p>First, we create a loading indicator when we click on the link (navigation element) component. You can see the loading indicator in the link component.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// components/loading-indicator.tsx</span>

<span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { Loader2Icon } <span class="hljs-keyword">from</span> <span class="hljs-string">"lucide-react"</span>;
<span class="hljs-keyword">import</span> { useLinkStatus } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LoadingIndicator</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { pending } = useLinkStatus();
  <span class="hljs-keyword">return</span> pending ? &lt;Loader2Icon className=<span class="hljs-string">"animate-spin"</span> /&gt; : <span class="hljs-literal">null</span>;
}
</code></pre>
<p>Use the LoadingIndicator component inside the Link component. When the user clicks on the navigation, you will see the loading indicator.</p>
<pre><code class="lang-typescript">&lt;Link
  href=<span class="hljs-string">"/"</span>
  className=<span class="hljs-string">"hover:underline hover:underline-offset-2"</span>
  prefetch={<span class="hljs-literal">false</span>}
&gt;
  &lt;Button className=<span class="hljs-string">"rounded"</span> size=<span class="hljs-string">"lg"</span>&gt; 
    &lt;HomeIcon className=<span class="hljs-string">"mr-2 h-4 w-4"</span> /&gt; {<span class="hljs-comment">/* show icon */</span>}
    &lt;LoadingIndicator /&gt; {<span class="hljs-comment">/* Show the indicator */</span>}
    Home
  &lt;/Button&gt;
&lt;/Link&gt;
</code></pre>
<p>After combining the LoadingIndicator and Link components, your header component code looks like this.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// components/Header.tsx</span>

<span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;
<span class="hljs-keyword">import</span> LoadingIndicator <span class="hljs-keyword">from</span> <span class="hljs-string">"./loading-indicator"</span>;
<span class="hljs-keyword">import</span> { CircleUserRound, HomeIcon, NotebookPen } <span class="hljs-keyword">from</span> <span class="hljs-string">"lucide-react"</span>;
<span class="hljs-keyword">import</span> { Button } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ui/button"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Header</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;header className=<span class="hljs-string">"container flex justify-center items-center p-4"</span>&gt;
      &lt;div className=<span class="hljs-string">"max-w-2xl flex gap-5 mx-auto"</span>&gt;
        &lt;Link
          href=<span class="hljs-string">"/"</span>
          className=<span class="hljs-string">"hover:underline hover:underline-offset-2"</span>
          prefetch={<span class="hljs-literal">false</span>}
        &gt;
          &lt;Button className=<span class="hljs-string">"rounded"</span> size=<span class="hljs-string">"lg"</span>&gt;
            &lt;HomeIcon className=<span class="hljs-string">"mr-2 h-4 w-4"</span> /&gt;
            &lt;LoadingIndicator /&gt;
            Home
          &lt;/Button&gt;
        &lt;/Link&gt;
        &lt;Link
          href=<span class="hljs-string">"/posts"</span>
          className=<span class="hljs-string">"hover:underline hover:underline-offset-2"</span>
          prefetch={<span class="hljs-literal">false</span>}
        &gt;
          &lt;Button className=<span class="hljs-string">"rounded"</span> size=<span class="hljs-string">"lg"</span>&gt;
            &lt;NotebookPen className=<span class="hljs-string">"mr-2 h-4 w-4"</span> /&gt;
            &lt;LoadingIndicator /&gt;
            Posts
          &lt;/Button&gt;
        &lt;/Link&gt;
        &lt;Link
          href=<span class="hljs-string">"/about"</span>
          className=<span class="hljs-string">"hover:underline hover:underline-offset-2"</span>
          prefetch={<span class="hljs-literal">false</span>}
        &gt;
          &lt;Button className=<span class="hljs-string">"rounded"</span> size=<span class="hljs-string">"lg"</span>&gt;
            &lt;CircleUserRound className=<span class="hljs-string">"mr-2 h-4 w-4"</span> /&gt;
            &lt;LoadingIndicator /&gt;
            About
          &lt;/Button&gt;
        &lt;/Link&gt;
      &lt;/div&gt;
    &lt;/header&gt;
  );
}
</code></pre>
<p>Finally, use the header component in the <code>layout.tsx</code> file.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/layout.tsx </span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"./globals.css"</span>;
<span class="hljs-keyword">import</span> { Header } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Header"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{
  children,
}: Readonly&lt;{
  children: React.ReactNode;
}&gt;</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;html suppressHydrationWarning={<span class="hljs-literal">true</span>} lang=<span class="hljs-string">"en"</span>&gt;
      &lt;body&gt;
        &lt;Header /&gt;
        {children}
      &lt;/body&gt;
    &lt;/html&gt;
  );
}
</code></pre>
<h1 id="heading-next-14">Next 14</h1>
<p>Next 14 was released on October 26, 2023, and during the <a target="_blank" href="https://www.youtube.com/watch?v=8q2q_820Sx4&amp;t=1387s&amp;ab_channel=Vercel">Next.js Conf</a>, Guillermo Rauch, the CEO, talked about the new features. One of the new features, termed “Partial Prerendering“, was introduced in the preview with the goal of providing both quick initial and dynamic visuals without sacrificing the developer experience.</p>
<p>Next.js 14 brings notable improvements to its TuporPack, the engine responsible for efficient compilation, now it is now faster. Furthermore, the stabilization of Server Actions and partial prerendering results in a better experience and better websites.</p>
<h2 id="heading-partial-pre-rendering">Partial Pre-rendering</h2>
<p>Partial prerendering is a technique that enhances the performance and user experience of dynamic web pages by extracting the static elements, such as logos, icons, page navigation, and fallbacks of dynamic slots. These elements are used to create a static shell, which can be delivered to users without delay. Meanwhile, the server continues to load the dynamic content in the background and displays it progressively when ready. With the ongoing debate between SSR and SSG, Next.js has decided to bring you the benefits of both worlds.</p>
<p>Here is the <code>app/CatFacts.tsx</code> file, which includes a component that interacts with a public API and showcases captivating cat facts from its response:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">1000</span>));

  <span class="hljs-comment">// call public API to retrieve cat facts and ensure cache is disabled</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://cat-fact.herokuapp.com/facts/'</span>, { cache: <span class="hljs-string">'no-store'</span> });

  <span class="hljs-keyword">if</span> (!res.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to fetch data'</span>);
  }

  <span class="hljs-keyword">return</span> res.json();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">CatFacts</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call API inside the React component</span>
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData();

  <span class="hljs-keyword">return</span> (
    &lt;ul className=<span class="hljs-string">"list-disc"</span>&gt;
      {data.map(<span class="hljs-function">(<span class="hljs-params">{ text, _id }: { text: <span class="hljs-built_in">string</span>; _id: <span class="hljs-built_in">string</span> }</span>) =&gt;</span> (
        &lt;li key={_id}&gt;{text}&lt;/li&gt;
      ))}
    &lt;/ul&gt;
  );
}
</code></pre>
<p>Here is the fallback display of the <code>CatFacts</code> component before the page is rendered, available in the <code>app/CatFactsSkeleton.tsx</code> file.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">CatFactsSkeleton</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> &lt;p&gt;Loading Cat Facts...&lt;/p&gt;
}
</code></pre>
<p>Here is the modified <code>app/page.tsx</code> file, which displays the <code>CatFacts</code> component, along with its fallback UI.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> CatFacts <span class="hljs-keyword">from</span> <span class="hljs-string">'./CatFacts'</span>;
<span class="hljs-keyword">import</span> CatFactsSkeleton <span class="hljs-keyword">from</span> <span class="hljs-string">'./CatFactsSkeleton'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"flex items-center p-24"</span>&gt;
      &lt;Suspense fallback={&lt;CatFactsSkeleton /&gt;}&gt;
        &lt;CatFacts /&gt;
      &lt;/Suspense&gt;
    &lt;/main&gt;
  );
}
</code></pre>
<p>Build the production version of the app:</p>
<pre><code class="lang-typescript">% yarn build
yarn run v1<span class="hljs-number">.22</span><span class="hljs-number">.10</span>
warning ../package.json: No license field
$ next build
   ▲ Next.js <span class="hljs-number">14.1</span><span class="hljs-number">.1</span>-canary<span class="hljs-number">.17</span>

   Creating an optimized production build ...
 ✓ Compiled successfully
 ✓ Linting and checking validity <span class="hljs-keyword">of</span> types    
 ✓ Collecting page data    
 ✓ Generating <span class="hljs-keyword">static</span> pages (<span class="hljs-number">5</span>/<span class="hljs-number">5</span>) 
 ✓ Collecting build traces    
 ✓ Finalizing page optimization    

Route (app)                              Size     First Load JS
┌ λ /                                    <span class="hljs-number">136</span> B          <span class="hljs-number">85.1</span> kB
└ ○ /_not-found                          <span class="hljs-number">885</span> B          <span class="hljs-number">85.9</span> kB
+ First Load JS shared by all            <span class="hljs-number">85</span> kB
  ├ chunks/<span class="hljs-number">54</span><span class="hljs-number">-42</span>de27d3a1832522.js        <span class="hljs-number">29.8</span> kB
  ├ chunks/fd9d1056<span class="hljs-number">-9e0</span>d44545602dadc.js  <span class="hljs-number">53.4</span> kB
  └ other shared chunks (total)          <span class="hljs-number">1.86</span> kB


○  (Static)   prerendered <span class="hljs-keyword">as</span> <span class="hljs-keyword">static</span> content
λ  (Dynamic)  server-rendered on demand using Node.js

✨  Done <span class="hljs-keyword">in</span> <span class="hljs-number">13.16</span>s.
jenniferfu<span class="hljs-meta">@jenniferfu</span> my-next-app % yarn start
yarn run v1<span class="hljs-number">.22</span><span class="hljs-number">.10</span>
warning ../package.json: No license field
$ next start
   ▲ Next.js <span class="hljs-number">14.1</span><span class="hljs-number">.1</span>-canary<span class="hljs-number">.17</span>
   - Local:        http:<span class="hljs-comment">//localhost:3000</span>

 ✓ Ready <span class="hljs-keyword">in</span> <span class="hljs-number">394</span>ms
</code></pre>
<p>Execute the command <code>yarn start</code> to start the production server. Instantly, the fallback UI appears, followed by the <code>CatFacts</code> component once it is rendered.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:960/1*X1g3SK42JBs9q2b0WNonDw.gif" alt class="image--center mx-auto" /></p>
<p>Generate a Lighthouse report to analyze and audit the web page,and it shows a flawless performance score:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750161783126/1a757e40-f2e4-4ffa-811d-35c348564db9.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-turbo-mode">Turbo Mode</h2>
<p><a target="_blank" href="https://turbo.build/pack">Turbopack</a> is an innovative bundler specifically designed for JavaScript and TypeScript, developed in Rust by the creators of Webpack and Next.js. It serves as a compelling alternative to Webpack, offering substantial improvements in cold start and Hot Module Replacement (HMR) performance.</p>
<p>The exceptional performance of Turbopack can be attributed to two primary factors. First, it leverages highly optimized machine code to ensure efficient execution. Second, it incorporates a sophisticated low-level incremental computation engine that enables caching at the granularity of individual functions. As a result, once Turbopack completes a task, it never needs to repeat it. With Turbopack, we can significantly enhance the speed of an application’s startup and seamlessly handle module updates during development.</p>
<p>The following execution demonstrates that a cold start of the out-of-box application typically takes <code>1886</code> milliseconds without Turbopack:</p>
<pre><code class="lang-typescript">% yarn dev  
yarn run v1<span class="hljs-number">.22</span><span class="hljs-number">.10</span>
warning ../package.json: No license field
$ next dev
   ▲ Next.js <span class="hljs-number">14.1</span><span class="hljs-number">.0</span>
   - Local:        http:<span class="hljs-comment">//localhost:3000</span>

 ✓ Ready <span class="hljs-keyword">in</span> <span class="hljs-number">1886</span>ms
</code></pre>
<p>The following execution shows that the cold start can be reduced to <code>915ms</code> with Turbopack:</p>
<pre><code class="lang-typescript">% yarn dev --turbo
yarn run v1<span class="hljs-number">.22</span><span class="hljs-number">.10</span>
warning ../package.json: No license field
$ next dev --turbo
   ▲ Next.js <span class="hljs-number">14.1</span><span class="hljs-number">.0</span> (turbo)
   - Local:        http:<span class="hljs-comment">//localhost:3000</span>

 ✓ Ready <span class="hljs-keyword">in</span> <span class="hljs-number">915</span>ms
</code></pre>
<p>The performance enhancement reaches a significant 51.5%, nearly matching the official benchmark achieved with Turbopack:</p>
<ul>
<li><p>Up to 53.3% faster local server startup</p>
</li>
<li><p>Up to 94.7% faster code updates with Fast Refresh</p>
</li>
</ul>
<p>Turpoback has successfully completed over 5000 integration tests for App and Pages Router, accounting for <a target="_blank" href="https://areweturboyet.com/">92.6% of the total tests</a>. Once it achieves 100% pass rates, Turpopack will be considered stable and will be released in an upcoming minor release.</p>
<h2 id="heading-stable-server-actions">Stable Server Actions</h2>
<p>Server Actions, also known as Server Side Rendering (SSR) functions, were introduced in Next.js 13 but they had some bugs and stability issues. In Next.js 14, Server Actions have reached production stability.</p>
<p>Developers can now define reusable server-side logic directly in their React components. This provides a seamless way to handle data fetching, API requests, and other server-side tasks without having to create separate API route files. It’s a game-changer for the developer experience. The stability improvements in Next.js 14 make it ready for production use cases. Error handling is also improved with consistent error messages.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/page.tsx</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params">formData: FormData</span>) </span>{
    <span class="hljs-string">'use server'</span>;
    <span class="hljs-keyword">await</span> db.form.insertOne({ formData });
  }
  <span class="hljs-keyword">return</span> (
    &lt;form action={create}&gt;
      &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span> name=<span class="hljs-string">"name"</span> /&gt;
      &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
  );
}
</code></pre>
<h2 id="heading-app-router-data-fetching-amp-streaming">App Router, Data Fetching &amp; Streaming</h2>
<p>Next.js, powered by <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/rendering/server-components">React Server Components</a>, revolutionizes web development by providing unparalleled features such as shared layouts, nested routing, loading states, error handling, and a plethora of other capabilities. To bring this visionary concept to life, Next.js relies on three essential parts:</p>
<ul>
<li><p>The App Router</p>
</li>
<li><p>Data Fetching System</p>
</li>
<li><p>Streaming Architecture</p>
</li>
</ul>
<h3 id="heading-the-app-router">The App Router</h3>
<p>The App Router is a built-in router system that defines and handles routes in a Next.js application. It is responsible for mapping URLs to specific pages or components in the application. The App Router enhances the overall user experience. Its introduction in Next.js 13.4 firmly established its credibility, earning it recommendations ever since.</p>
<p>The App Router, located in the <code>app</code> directory, utilizes a folder structure that mirrors the segments of a URL path for seamless routing. It accommodates nested routes by organizing folders within one another. Furthermore, apart from designated files, we can conveniently place our own files (such as components, styles, tests, etc.) within the <code>app</code> directory’s folders.</p>
<p><a target="_blank" href="https://medium.com/render-beyond/mastering-next-js-c7cba322a103">https://medium.com/render-beyond/mastering-next-js-c7cba322a103</a></p>
<h3 id="heading-streaming-architecture">Streaming Architecture</h3>
<p>Streaming architecture allows for incremental rendering and delivering components to the client as soon as they are ready. It provides faster page loading times by breaking down the rendering process into smaller chunks and streaming them to the client progressively. With streaming architecture, Next.js takes advantage of the streaming capabilities of Node.js and the HTTP/2 protocol to send the rendered content to the client in chunks, allowing the user to see and interact with the page while it is fetching data.</p>
<h3 id="heading-data-fetching-system">Data Fetching System</h3>
<p>Next.js 14 introduces an improved data fetching system, aimed at enhancing the developer experience when working with data mutations. This system eliminates the need for manually creating an API route. Rather than creating an additional file, developers can simply define a server-side function in the component file and call it directly from a React component. This update effectively simplifies the data fetching workflow and allows for more efficient development.</p>
<p>Below is the modified <code>app/page.tsx</code> file that defines the server-side function <code>getData</code>, which fetches cat facts from a public API <a target="_blank" href="https://cat-fact.herokuapp.com/facts/"><code>https://cat-fact.herokuapp.com/facts/</code></a>. The <code>Home</code> component calls <code>getData</code> directly without writing an extra API route.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call the public API to fetch cat facts</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://cat-fact.herokuapp.com/facts/'</span>);

  <span class="hljs-keyword">if</span> (!res.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to fetch data'</span>);
  }

  <span class="hljs-keyword">return</span> res.json();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call API inside the React component</span>
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData();

  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"flex items-center p-24"</span>&gt;
      &lt;ul className=<span class="hljs-string">"list-disc"</span>&gt;
        {data.map(<span class="hljs-function">(<span class="hljs-params">{ text, _id }: { text: <span class="hljs-built_in">string</span>; _id: <span class="hljs-built_in">string</span> }</span>) =&gt;</span> (
          &lt;li key={_id}&gt;{text}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/main&gt;
  );
}
</code></pre>
<p>Execute the command <code>yarn dev --turbo</code>, and we see cat facts at <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a>.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*WUH6iJLBDqbBeyrwpISGkw.png" alt /></p>
<p>What if there is an error in retrieving data?</p>
<p>Change the fetch URL to <a target="_blank" href="https://cat-fact.herokuapp_error.com/facts/"><code>https://cat-fact.herokuapp_error.com/facts/</code></a>, and we see the following error in the browser:</p>
<pre><code class="lang-typescript">Unhandled Runtime <span class="hljs-built_in">Error</span>
<span class="hljs-built_in">Error</span>: Failed to fetch data

Call Stack
getData
/Users/jenniferfu/my-next-app/.next/server/chunks/[root <span class="hljs-keyword">of</span> the server]__9d686c._.js (<span class="hljs-number">87</span>:<span class="hljs-number">15</span>)
process.processTicksAndRejections
node:internal/process/task_queues (<span class="hljs-number">95</span>:<span class="hljs-number">5</span>)
<span class="hljs-keyword">async</span> Home
/Users/jenniferfu/my-next-app/.next/server/chunks/[root <span class="hljs-keyword">of</span> the server]__9d686c._.js (<span class="hljs-number">92</span>:<span class="hljs-number">18</span>)
</code></pre>
<p>The data fetching system not only retrieves data but also incorporates caching and invalidation capabilities. Let’s provide examples illustrating the functioning of data caching.</p>
<ol>
<li><strong>Caches by default</strong></li>
</ol>
<p>Next.js includes a convenient built-in data cache that stores the results of data fetched from incoming server requests and deployments. By default, a fetch result is stored in the data cache on the server to improve performance and prevent unnecessary re-fetching of data.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 'force-cache' is the default, and can be omitted</span>
fetch(<span class="hljs-string">'https://...'</span>, { cache: <span class="hljs-string">'force-cache'</span> })
</code></pre>
<p>In the following <code>app/page.tsx</code> file, we have used the public API <a target="_blank" href="http://www.randomnumberapi.com/api/v1.0/random"><code>http://www.randomnumberapi.com/api/v1.0/random</code></a> to generate a unique random number each time it is called. In addition, we have implemented a component to combine the results of two API calls.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call the public API to fetch a random number</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'http://www.randomnumberapi.com/api/v1.0/random'</span>);

  <span class="hljs-keyword">if</span> (!res.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to fetch data'</span>);
  }

  <span class="hljs-keyword">return</span> res.json();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call API twice inside the React component</span>
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData();
  <span class="hljs-keyword">const</span> data2 = <span class="hljs-keyword">await</span> getData();

  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"flex items-center p-24"</span>&gt;
      &lt;ul className=<span class="hljs-string">"list-disc"</span>&gt;
        {[...data, ...data2].map((<span class="hljs-function">(<span class="hljs-params">value: <span class="hljs-built_in">number</span>, id: <span class="hljs-built_in">number</span></span>) =&gt;</span> (
          &lt;li key={id}&gt;{value}&lt;/li&gt;
        )))}
      &lt;/ul&gt;
    &lt;/main&gt;
  );
}
</code></pre>
<p>When executing the command <code>yarn dev --turbo</code>, it appears that the random number generated remains the same with each call. Additionally, the data persists even when the browser is refreshed, which may not be the desired behavior.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:578/1*01_xADxD6oJZ_Q7sKfj1fQ.png" alt class="image--center mx-auto" /></p>
<ol start="2">
<li><strong>Disabling caching</strong></li>
</ol>
<p>We have the option of <code>'no-store'</code> to disable caching.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Opt out of caching for an individual fetch request</span>
fetch(<span class="hljs-string">'https://...'</span>, { cache: <span class="hljs-string">'no-store'</span> })
</code></pre>
<p>Here is the modified <code>app/page.tsx</code> file:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call the public API to retrieve a random number and ensure cache is disabled</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'http://www.randomnumberapi.com/api/v1.0/random'</span>, { cache: <span class="hljs-string">'no-store'</span> });

  <span class="hljs-keyword">if</span> (!res.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to fetch data'</span>);
  }

  <span class="hljs-keyword">return</span> res.json();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call API twice inside the React component</span>
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData();
  <span class="hljs-keyword">const</span> data2 = <span class="hljs-keyword">await</span> getData();

  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"flex items-center p-24"</span>&gt;
      &lt;ul className=<span class="hljs-string">"list-disc"</span>&gt;
        {[...data, ...data2].map((<span class="hljs-function">(<span class="hljs-params">value: <span class="hljs-built_in">number</span>, id: <span class="hljs-built_in">number</span></span>) =&gt;</span> (
          &lt;li key={id}&gt;{value}&lt;/li&gt;
        )))}
      &lt;/ul&gt;
    &lt;/main&gt;
  );
}
</code></pre>
<p>When executing the command <code>yarn dev --turbo</code>, we observe that the random number changes with each call.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:578/1*5_Au6vMdkbsK7EMTawPDWw.png" alt class="image--center mx-auto" /></p>
<p>Alternatively, we can opt out of caching for a specific route segment, using the route segment config options.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> dynamic = <span class="hljs-string">'force-dynamic'</span>; <span class="hljs-comment">// disable caching</span>

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call public API to fetch a random number</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'http://www.randomnumberapi.com/api/v1.0/random'</span>);

  <span class="hljs-keyword">if</span> (!res.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to fetch data'</span>);
  }

  <span class="hljs-keyword">return</span> res.json();
}
</code></pre>
<ol start="3">
<li><strong>Time-based revalidation</strong></li>
</ol>
<p>We can also implement time-based revalidation to automatically fetch data after a specified interval. This approach proves beneficial for data that undergoes infrequent changes, where maintaining absolute real-time freshness is not as crucial.</p>
<p>Here is the modified <code>app/page.tsx</code> file:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call the public API to fetch a random number, and ensure its revalidation after one second</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'http://www.randomnumberapi.com/api/v1.0/random'</span>, { next: { revalidate: <span class="hljs-number">1</span> } });

  <span class="hljs-keyword">if</span> (!res.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to fetch data'</span>);
  }

  <span class="hljs-keyword">return</span> res.json();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call API twice inside the React component</span>
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData();
  <span class="hljs-keyword">const</span> data2 = <span class="hljs-keyword">await</span> getData();

  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"flex items-center p-24"</span>&gt;
      &lt;ul className=<span class="hljs-string">"list-disc"</span>&gt;
        {[...data, ...data2].map((<span class="hljs-function">(<span class="hljs-params">value: <span class="hljs-built_in">number</span>, id: <span class="hljs-built_in">number</span></span>) =&gt;</span> (
          &lt;li key={id}&gt;{value}&lt;/li&gt;
        )))}
      &lt;/ul&gt;
    &lt;/main&gt;
  );
}
</code></pre>
<p>To confirm, run the command <code>yarn dev --turbo</code> and observe that the random number remains constant for sequential calls made within a 1-second timeframe.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:578/1*iyzg9NNq87xZgcrM24wVgA.png" alt class="image--center mx-auto" /></p>
<p>However, the random numbers will change after a second by simply refreshing the browser.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:578/1*bFkihIDHr0wrBuOXrQUlxw.png" alt class="image--center mx-auto" /></p>
<ol start="4">
<li><strong>Revalidating tags</strong></li>
</ol>
<p>The <code>revalidateTag</code> API provides a convenient way to instantly invalidate cached data for a specific cache tag. Its tag parameter is expected to be a string that consists of 256 characters or less.</p>
<pre><code class="lang-typescript">revalidateTag(tag: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">void</span>;
</code></pre>
<p>Tags is an array of strings defined in the fetch request:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// define a list of tags</span>
fetch(url, { next: { tags: [<span class="hljs-string">'tag1'</span>, <span class="hljs-string">'tag2'</span>, ...] } });
</code></pre>
<p>Below is the modified <code>app/page.tsx</code> file, where the fetch request is tagged as <code>'number'</code>, and the cache is cleared after each fetch.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { revalidateTag } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/cache'</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call the public API to fetch a random number, and label the response with the tag 'number'</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'http://www.randomnumberapi.com/api/v1.0/random'</span>, { next: { tags: [<span class="hljs-string">'number'</span>] } });

  <span class="hljs-keyword">if</span> (!res.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to fetch data'</span>);
  }

  <span class="hljs-keyword">return</span> res.json();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call API inside the React component</span>
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData();
  revalidateTag(<span class="hljs-string">'number'</span>); <span class="hljs-comment">// revalidate the data cache</span>
  <span class="hljs-keyword">const</span> data2 = <span class="hljs-keyword">await</span> getData();
  revalidateTag(<span class="hljs-string">'number'</span>); <span class="hljs-comment">// revalidate the data cache</span>

  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"flex items-center p-24"</span>&gt;
      &lt;ul className=<span class="hljs-string">"list-disc"</span>&gt;
        {[...data, ...data2].map((<span class="hljs-function">(<span class="hljs-params">value: <span class="hljs-built_in">number</span>, id: <span class="hljs-built_in">number</span></span>) =&gt;</span> (
          &lt;li key={id}&gt;{value}&lt;/li&gt;
        )))}
      &lt;/ul&gt;
    &lt;/main&gt;
  );
}
</code></pre>
<p>When executing the command <code>yarn dev --turbo</code>, we observe that the random number changes with every call.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:578/1*tiZlWPgUD6d2kg8iHwqJrg.png" alt class="image--center mx-auto" /></p>
<ol start="5">
<li><strong>Revalidating path</strong></li>
</ol>
<p>Alternatively, the <code>revalidatePath</code> function can also be utilized to manually refresh cached data for a specific path.</p>
<pre><code class="lang-typescript">revalidatePath(path: <span class="hljs-built_in">string</span>, <span class="hljs-keyword">type</span>?: <span class="hljs-string">'page'</span> | <span class="hljs-string">'layout'</span>): <span class="hljs-built_in">void</span>;
</code></pre>
<ul>
<li><p><code>path</code>: It is either a string representing the filesystem path associated with the data to revalidate (for example, <code>/product/[slug]/page</code>), or the literal route segment (for example, <code>/product/123</code>). It must be less than 1024 characters.</p>
</li>
<li><p><code>type</code> (optional): It is a string of <code>'page'</code> or <code>'layout'</code> to specify the type of path to revalidate. If <code>path</code> contains a dynamic segment (for example, <code>/product/[slug]/page</code>), this parameter is required.</p>
</li>
</ul>
<p>Below is the modified <code>app/page.tsx</code> file, where the cache of the data path <code>/</code> is cleared after each fetch.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { revalidatePath } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/cache'</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// call the public API to fetch a random number</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'http://www.randomnumberapi.com/api/v1.0/random'</span>);

  <span class="hljs-keyword">if</span> (!res.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to fetch data'</span>);
  }

  <span class="hljs-keyword">return</span> res.json();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getData();
  revalidatePath(<span class="hljs-string">'/'</span>); <span class="hljs-comment">// revalidate the data path /</span>
  <span class="hljs-keyword">const</span> data2 = <span class="hljs-keyword">await</span> getData();
  revalidatePath(<span class="hljs-string">'/'</span>); <span class="hljs-comment">// revalidate the data path /</span>

  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"flex items-center p-24"</span>&gt;
      &lt;ul className=<span class="hljs-string">"list-disc"</span>&gt;
        {[...data, ...data2].map((<span class="hljs-function">(<span class="hljs-params">value: <span class="hljs-built_in">number</span>, id: <span class="hljs-built_in">number</span></span>) =&gt;</span> (
          &lt;li key={id}&gt;{value}&lt;/li&gt;
        )))}
      &lt;/ul&gt;
    &lt;/main&gt;
  );
}
</code></pre>
<p>When executing the command <code>yarn dev --turbo</code>, we observe that the random number changes with every call.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:578/1*q2kBmRQVKrtcKHz7mA88Xg.png" alt class="image--center mx-auto" /></p>
<ol start="6">
<li><strong>Stable APIs</strong></li>
</ol>
<p>Server actions are deeply integrated into the entire App Router model. Here is the summary of the server API calls:</p>
<ul>
<li><p>Revalidate cached data with <code>revalidatePath()</code> or <code>revalidateTag()</code></p>
</li>
<li><p>Redirect to different routes through <code>redirect()</code></p>
</li>
<li><p>Set and read cookies through <code>cookies()</code></p>
</li>
<li><p>Handle optimistic UI updates with <code>useOptimistic()</code></p>
</li>
<li><p>Catch and display errors from the server with <code>useFormState()</code></p>
</li>
<li><p>Display loading states on the client with <code>useFormStatus()</code></p>
</li>
</ul>
<h2 id="heading-metadata-improvements">Metadata Improvements</h2>
<p>Before your page content can be streamed from the server, there is important metadata about the viewport, color scheme, and theme that needs to be sent to the browser first.</p>
<p>Ensuring these meta tags are sent with the initial page content helps a smooth experience, preventing the page from flickering by changing the theme color or shifting layout due to viewport changes.</p>
<p>In Next.js 14, decoupled blocking and non-blocking metadata. Only a small subset of metadata options are blocking, and Next.js wants to make sure non-blocking metadata will not prevent a partially pre-rendered page from serving the static shell.</p>
<p>The following metadata options are now deprecated and will be removed from metadata in a future major version:</p>
<ul>
<li><p><code>viewport</code>: Sets the initial zoom and other properties of the viewport</p>
</li>
<li><p><code>colorScheme</code>: Sets the support modes (light/dark) for the viewport</p>
</li>
<li><p><code>themeColor</code>: Sets the color the chrome around the viewport should render with</p>
</li>
</ul>
<h2 id="heading-image-optimization-and-image-component">Image Optimization and Image Component</h2>
<p>Next.js 14 introduces an enhanced and flexible image optimization feature, streamlining the process of optimizing images automatically. Here’s a brief overview of how Next.js facilitates image optimization:</p>
<ol>
<li><strong>Prioritizing Image Loading</strong></li>
</ol>
<p>Next.js intelligently prioritizes image loading. Images within the viewport are loaded first, providing a faster initial page load, and images below are loaded asynchronously as the user scrolls down.</p>
<ol start="2">
<li><strong>Dynamic Sizing and Format Selection</strong></li>
</ol>
<p>The Image component in Next.js dynamically selects the right size and format based on the user’s bandwidth and device resources. This ensures that users receive appropriately sized and optimized images.</p>
<ol start="3">
<li><strong>Responsive Image Resizing</strong></li>
</ol>
<p>Next.js simplifies responsive image handling by automatically resizing images as needed. This responsive design approach ensures that images adapt to various screen sizes, further enhancing the overall user experience.</p>
<ol start="4">
<li><strong>Support for Next-Gen Formats (WebP):</strong></li>
</ol>
<p>The image optimization in Next.js extends to supporting next-generation image formats like WebP. This format, known for its superior compression and quality, is automatically utilized by the Image component when applicable.</p>
<ol start="5">
<li><strong>Preventing Cumulative Layout Shifts:</strong></li>
</ol>
<p>To enhance visual stability and prevent layout shifts, Next.js incorporates placeholders for images. These placeholders serve as temporary elements until the actual images are fully loaded, avoiding disruptions in the layout.</p>
<p>Additionally, Next.js 14 enhances performance by efficiently handling font downloads. The framework optimizes the download process for fonts from sources such as Next/font/google.</p>
<h2 id="heading-automatic-code-splitting">Automatic code splitting</h2>
<p>Automatic code splitting in Next.js 14 is a powerful technique that significantly contributes to optimizing web performance. As discussed in the <a target="_blank" href="https://calibreapp.com/blog/nextjs-performance#dynamically-load-client-side-code-to-reduce-first-load-javascript">Calibre blog post</a>, dynamic imports, also known as code-splitting, play a key role in this process.</p>
<p>Code-splitting results in breaking JS bundles into smaller, more manageable chunks. Users only download what’s necessary, leading to a more efficient use of bandwidth. With less JS, the performance on slower devices sees a notable improvement.</p>
<p>Another insightful article on <a target="_blank" href="https://www.builder.io/blog/fast-to-faster-what-you-need-to-do-to-improve-performance-in-nextjs">Builder.io</a> expands on the two methods of code-splitting in Next.js:</p>
<p><strong>Route-based splitting</strong>: By default, Next.js splits JavaScript into manageable chunks for each route. As users interact with different UI elements, the associated code chunks are sent, reducing the amount of code to be parsed and compiled at once.</p>
<p><strong>Component-based splitting:</strong> Developers can optimize even further on a component level. Large components can be split into separate chunks, allowing non-critical components or those rendering only on specific UI interactions to be lazily loaded as needed.</p>
<p>These approaches collectively contribute to a more efficient, faster, and user-friendly web application experience, aligning with the continuous efforts to enhance performance in Next.js 14.</p>
<p><a target="_blank" href="https://medium.com/render-beyond/mastering-next-js-c7cba322a103">https://medium.com/render-beyond/mastering-next-js-c7cba322a103</a></p>
<p><a target="_blank" href="https://medium.com/@sassenthusiast/my-epiphany-with-next-js-14s-server-components-08f69a2c1414">https://medium.com/@sassenthusiast/my-epiphany-with-next-js-14s-server-components-08f69a2c1414</a></p>
<h1 id="heading-nextjs-13">Next.js 13</h1>
<p>The Vercel team posted a major announcement on their blog about the release of Next.js 13.4. To provide more context about why this is such an important release, we need to understand how the Vercel team handles releases to the public. Next.js 13 introduced so many new features, but most of them have remained in the alpha &amp; beta versions, even though they were included in the major release.</p>
<p>So despite the fact that Next.js dropped some major new upgrades in Version 13 last October, the features have not quite been ready for prime time. Those changes in Next.js 13.4! The new 13.4 release finally provides a stable release of one of the most important new features: the App Router.</p>
<p>In this section, we will dive into some of the new features and improvements that come with this release. From the first stable release of the new app directory and app router to the latest advancements in Turpoback, there is a lot to be excited about. Let’s get started.</p>
<h2 id="heading-the-new-app-router">The New App Router</h2>
<p>As mentioned, Next.js 13.4 is the first release that takes the new app directory and app router features out of beta!</p>
<p>As someone who has been playing with these features in sample projects, I can tell you that I have been getting antsy waiting to use them in production because they make the development experience in Next that much better.</p>
<p>Also, perhaps symbolic of the importance of this release, the Next.js <a target="_blank" href="https://nextjs.org/docs">document site</a> has a major update to make the App Router the default! You can now toggle the docs between the new app Router and the previous Page Router.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*NevF5rAsd2yr8EuglkotzA.png" alt /></p>
<p>Below, we will do a quick recap of the app router by diving into some of the main features.</p>
<h3 id="heading-routing-in-the-app-directory">Routing in the app directory</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750502267284/0f9c5368-7a44-4156-8b64-cf97d781fa98.webp" alt class="image--center mx-auto" /></p>
<p>Routing in the new app directory is as simple as adding the <code>page.tsx</code> file that exports a React function component. The routing of the application is defined by the hierarchy of your folders within the app directory. For example, creating a page at the / route is as easy as adding a file page.tsx file at the root of the app directory.</p>
<pre><code class="lang-typescript">.
└── app/
    └── page.tsx
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/page.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> &lt;SomeJsx /&gt;
}
</code></pre>
<p>Next, let’s show how we can create more complex application routes using the new app router:</p>
<pre><code class="lang-typescript">.
└── app/
    ├── page.tsx
    ├── about/
    │   ├── page.tsx
    │   └── layout.tsx
    └── articles/
        └── article/
            └── [id]/
                ├── page.tsx
                ├── layout.tsx
                └── components/
                    ├── BlogArticle.tsx
                    └── Author.tsx
</code></pre>
<p>As you can see above, we are able to create a simple route such as <code>/about</code>, as well as create more complex routes like <code>/articles/article/12345</code> using Next.js’ <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes">dynamic routes</a>.</p>
<p>With the new App Router, our pages can make use of <a target="_blank" href="https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components">React Server Components</a>, which allows us to simplify data fetching using the familiar async/await syntax.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/page.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/...'</span>);
  <span class="hljs-keyword">const</span> data = res.json();
  <span class="hljs-keyword">return</span> <span class="hljs-string">'...'</span>;
}
</code></pre>
<p>In Next.js 13, files are server components by default. You can opt into client components by including the <code>'use client'</code> directive at the top of your module.</p>
<pre><code class="lang-typescript"><span class="hljs-string">'use client'</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ClientComponent</span>(<span class="hljs-params">{ id }: ArticleProps</span>) </span>{
  useEffect(<span class="hljs-function">() =&gt;</span> { <span class="hljs-comment">//... }, [])</span>
  <span class="hljs-keyword">return</span> <span class="hljs-comment">//...</span>
}
</code></pre>
<p>Also, notice in our sample file tree above, we added components to our blog article folder. This was difficult in previous versions of Next.js because all files within the page directory were considered pages. Next.js 13 makes this a nicer experience by enforcing special file names for <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts">layout, page, template</a>, etc.</p>
<h3 id="heading-route-segment-configuration">Route segment configuration</h3>
<p>Our pages can also export route segments that allow us to control how the pages render. One common practice in Next.js is to statically generate pages. We run into an issue when we use dynamic params, though. How would Next.js know what pages to statically generate? We can make use of <code>generateStaticParams</code> to solve this.</p>
<p>In the example below, we export an async function called <code>generateStaticParams</code> that loads all of our blog articles and returns an array of objects with a property that matches the name of our dynamic route segment, in this case <code>id</code>. Next.js will use this to statically generate pages for each of our blog articles.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/articles/article/[id]/page.tsx</span>
<span class="hljs-keyword">type</span> ArticleProps = Pick&lt;Article, <span class="hljs-string">'id'</span>&gt;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params">{ id }: ArticleProps</span>) </span>{
  <span class="hljs-keyword">const</span> article = <span class="hljs-keyword">await</span>(<span class="hljs-keyword">await</span> fetchArticleById(id)).json();
  <span class="hljs-keyword">return</span> &lt;BlogArticle article={article} /&gt;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateStaticParams</span>(<span class="hljs-params"></span>): <span class="hljs-title">ArticleProps</span>[] </span>{
  <span class="hljs-keyword">const</span> articles = <span class="hljs-keyword">await</span>(<span class="hljs-keyword">await</span> fetchArticles()).json();
  <span class="hljs-keyword">return</span> articles.map(<span class="hljs-function"><span class="hljs-params">article</span> =&gt;</span> ({ id: article.id }))
}
</code></pre>
<p>Next.js 13 gives us several route <a target="_blank" href="https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config">segment configuration</a> options to control how Next.js renders the page. Aside from <code>generateStaticParams</code>, the most commonly used route segment configuration that I’ve been using is <code>revalidate</code>. When combined with Static Site Generation (SSG), revalidate allows you to control how of the page will get regenerated.</p>
<p>Building on our previous example, we can set revalidate to 60 seconds to rebuild the page every 60 seconds. Note that it’s a bit more nuanced than that, so make sure to read up on ISR on the Next.js documentation site.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/articles/article/page.tsx</span>
<span class="hljs-keyword">type</span> ArticleProps = Pick&lt;Article, <span class="hljs-string">'id'</span>&gt;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params">{ id }: ArticleProps</span>) </span>{
  <span class="hljs-keyword">const</span> article = <span class="hljs-keyword">await</span>(<span class="hljs-keyword">await</span> fetchArticleById(id)).json();
  <span class="hljs-keyword">return</span> &lt;BlogArticle article={article} /&gt;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateStaticParams</span>(<span class="hljs-params"></span>): <span class="hljs-title">ArticleProps</span>[] </span>{
  <span class="hljs-keyword">const</span> articles = <span class="hljs-keyword">await</span>(<span class="hljs-keyword">await</span> fetchArticles()).json();
  <span class="hljs-keyword">return</span> articles.map(<span class="hljs-function"><span class="hljs-params">article</span> =&gt;</span> ({ id: article.id }))
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> revalidate = <span class="hljs-number">60</span>
</code></pre>
<p>We can tell Next.js not to render pages for IDs that are not returned in generateStaticParams by making use of the <a target="_blank" href="https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamicparams">dynamicParams route segment configuration</a>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> dynamicParams = <span class="hljs-literal">false</span>
</code></pre>
<p>Finally, we can force the page to generate statically or dynamically, depending on our use case. For example, if we have a page that is making use of query params, we may want it to be dynamically server rendered when the page is requested using the <a target="_blank" href="https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic">dynamic route segment</a>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> dynamic = <span class="hljs-string">'force-dynamic'</span>
<span class="hljs-comment">// or: 'auto' | 'force-dynamic' | 'error' | 'force-static'</span>
</code></pre>
<h3 id="heading-layouts-and-templates">Layouts and Templates</h3>
<p>Along with pages, Next.js 13 also introduced special files for layouts and templates. In the example above, you may have noticed that we include several <code>layout.tsx</code> files at the various levels of the folder hierarchy. We created a root-level <code>layout.tsx</code>, which is a typical practice in Next.js 13.</p>
<p>Within the root layout, we can create the HTML document, add scripts and other content to the head, provide semantic structure, and wrap the app in providers. We no longer have to make use of the special <code>&lt;Head /&gt;</code> and <code>&lt;Script /&gt;</code> components from previous versions of Next. We can also add metadata here, but Next.js 13.2 introduced a new dynamic <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/optimizing/metadata#dynamic-metadata">Metadata API</a> for this that we will cover in another article.</p>
<p>Note that layouts and pages should typically be server components, so you should avoid forcing them to be client components by adding hooks or other client-only functionality.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/layout.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;html lang=<span class="hljs-string">"en"</span>&gt;
      &lt;head&gt;
        &lt;script&gt;<span class="hljs-comment">//...&lt;/script&gt;</span>
      &lt;/head&gt;
      &lt;body&gt;
        &lt;main&gt;
           &lt;AppProvider&gt;{children}&lt;/AppProvider&gt;
        &lt;/main&gt;      
      &lt;/body&gt;
    &lt;/html&gt;
  );
}

<span class="hljs-comment">// app/page.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-comment">//...;</span>
}
</code></pre>
<p>Layout files can be added at each level of the app directory’s hierarchy to apply more specific layouts to different parts of the application. For example, let’s say that we want to add a specific AppWrapper surrounding our blog articles. We can add a new <code>layout.tsx</code> file to the <code>/app/articles/article/[id]</code> directory next to the <code>page.tsx</code> file.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/articles/article/[id]/layout.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;AppWrapper&gt;{children}&lt;/AppWrapper&gt;
  );
}
</code></pre>
<p>Similar to layouts, templates allow you to create a shared structure. We will not go into them deeply here, so I suggest you read up on them on the <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#templates">Next.js documentation website</a>.</p>
<h3 id="heading-automatic-code-splitting-1">Automatic Code Splitting</h3>
<p>Next.js 13.4 also makes it easier than ever to code split and dynamically load content. In previous versions of Next.js, you had to make sense of <code>next/dynamic</code>. With Next.js 13, the entire application can opt into code splitting and dynamic loading by making use of <code>Suspense</code>. In fact, you can code split with a simple conditional within a client component. Check out the example below from the <a target="_blank" href="https://nextjs.org/blog/next-13-4#automatic-server-rendering-and-code-splitting">Next.js blog</a>, which returns completely different bundles depending on whether the user is logged in or not.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/layout.tsx</span>
<span class="hljs-keyword">import</span> { getUser } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth'</span>;
<span class="hljs-keyword">import</span> { Dashboard, Landing } <span class="hljs-keyword">from</span> <span class="hljs-string">'./components'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Layout</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> isLoggedIn = <span class="hljs-keyword">await</span> getUser();
  <span class="hljs-keyword">return</span> isLoggedIn ? &lt;Dashboard /&gt; : &lt;Landing /&gt;;
}
</code></pre>
<h3 id="heading-route-groups">Route Groups</h3>
<p><a target="_blank" href="https://nextjs.org/docs/app/building-your-application/routing/route-groups">Route Groups</a> are a nifty feature introduced in Next.js 13, especially when your app requires multiple root layouts. Next.js 13.3 removed the deprecated <code>head.js</code> special file and replaced it with the <code>generateMetadata</code> API. One downside of this approach is that it made it difficult to add scripts and other things to the <code>&lt;head /&gt;</code> when you had pages that had different content.</p>
<p>For example, let’s say part of your app has navigation that is loaded from an API. The API returns its content for its script dependencies. Route Groups give a solution to this problem by allowing you to split parts of your apps into different folders that have their own root layouts.</p>
<pre><code class="lang-typescript">.
├── (navigation)/
│   ├── dashboard/
│   │   └── page.tsx
│   └── layout.tsx
└── (navless)/
    ├── auth/
    │   └── page.tsx
    └── layout.tsx
</code></pre>
<p>In the example above, the dashboard page has its own root layout that can include the additional head content loaded from your API:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { PropsWithChildren } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Layout</span>(<span class="hljs-params">{ children }: PropsWithChildren</span>) </span>{
  <span class="hljs-keyword">const</span> { head, header, footer } = <span class="hljs-keyword">await</span> fetchNavigationMarkup()

  <span class="hljs-keyword">return</span> (
    &lt;html&gt;
      &lt;head&gt;
        {head}
      &lt;/head&gt;
      &lt;body&gt;
        {header}
        {children}
        {footer}
      &lt;/body&gt;
    &lt;/html&gt;
  )
}
</code></pre>
<h2 id="heading-react-server-components-rsc">React Server Components (RSC)</h2>
<p>The new Next.js 13 App Router was built in close partnership with React 18. One of the major new features of React 18 is React Server Components (RSC). In order to start working in Next.js 13, you need to wrap your head around this new paradigm.</p>
<p>In the past, React was primarily a client-side UI rendering library. With the addition of RSCs, the intention is to render as much of your application as possible on the server at build time (we will go into the different rendering modes more below)</p>
<blockquote>
<p>When a route is loaded with Next.js, the initial HTML is rendered on the server. This HTML is the progressively enhanced in the browser, allowing the client to take over the application and add interactivity, by asynchronously loading the Next.js and React client-side runtime.</p>
<p>From the <a target="_blank" href="https://nextjs.org/docs/getting-started/react-essentials">React Essentials Section</a> on the Next.js documentation site.</p>
</blockquote>
<p>In React 18, two new directives, “use client“ and “use server“ were added in order to control where components are rendered at the file level. These new directives are used in Next.js 13 to control whether the bundle code is included in the client-side bundle or not.</p>
<p>With the “use server“ directive, we can indicate that a component does not need to be included in the bundle that the client loads. The component will be rendered on the server at build or run time.</p>
<p>As you can see in the code above, we can also make use of <code>async await</code> in Server Components, which makes them great for loading data.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ServerComponent.ts</span>
<span class="hljs-string">"use server"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ServerComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchData()

  <span class="hljs-keyword">return</span> <span class="hljs-comment">//...</span>
}
</code></pre>
<p>If a component needs to make use of React Hooks, such as <code>useEffect</code>, or it needs to access browser APIs, we can use the “use client“ directive in order to indicate that the component should be included in the client bundle.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ClientComponent.tsx</span>
<span class="hljs-comment">// use client is needed here since we are using React hooks and accessing</span>
<span class="hljs-comment">// the localStorage browser API</span>
<span class="hljs-string">"use client"</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ClientComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todos, setTodos] = useState([])
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> cachedTodos = <span class="hljs-built_in">localStorage</span>.get(<span class="hljs-string">'todos'</span>)
    setTodos(todos)
  })

  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      {todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> &lt;Todo {...todo} /&gt;)}
    &lt;/&gt;
  )
}
</code></pre>
<p>See the original React RFC where these directives were proposed for more information: <a target="_blank" href="https://github.com/reactjs/rfcs/pull/227">https://github.com/reactjs/rfcs/pull/227</a></p>
<p><a target="_blank" href="https://tushar-tmpatel.medium.com/what-is-server-components-vs-client-components-in-next-js-13-24a5e0113105">https://tushar-tmpatel.medium.com/what-is-server-components-vs-client-components-in-next-js-13-24a5e0113105</a></p>
<h3 id="heading-server-components-are-the-default-in-nextjs">Server Components are the default in Next.js</h3>
<p>In the world of Next.js 13, server components are now the default, which means that most of your components should not need a “use server“ or “use client“ directive.</p>
<p>The only time you need to use these directives is when you are creating a boundary component.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// page.tsx</span>
<span class="hljs-comment">// React Server Component, will not be included in the client </span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-keyword">return</span> (
    &lt;Provider&gt;
      &lt;TodoList /&gt;
    &lt;/Provider&gt;
  )
}

<span class="hljs-comment">// TodoList.tsx</span>
<span class="hljs-comment">// use client is needed here since we are using React hooks</span>
<span class="hljs-string">"use client"</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoList</span>(<span class="hljs-params"></span>) </span>{
  useEffect(<span class="hljs-function">() =&gt;</span> {})

  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      {todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> &lt;Todo {...todo} /&gt;)}
    &lt;/&gt;
  )
}

<span class="hljs-comment">// TodoList.tsx</span>
<span class="hljs-comment">// No "use client" needed here, even though we are using hooks</span>
<span class="hljs-comment">// because this component is only ever rendered within another client component</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Todo</span>(<span class="hljs-params"></span>) </span>{
  useEffect(<span class="hljs-function">() =&gt;</span> {})

  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      {todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> &lt;Todo {...todo} /&gt;)}
    &lt;/&gt;
  )
}
</code></pre>
<h3 id="heading-client-components-are-rendered-on-the-server-too">Client Components are rendered on the server, too</h3>
<p>When you use a “use client“ directive to make a client component, it doesn’t means that it only renders on the client side. In fact, most client components are rendered on the server when doing server-side rendering (SSR) or static site generation (SSG).</p>
<p>The only time a client component will not be rendered on the server is when you specifically instruct it not to. One way to do this is by making use of <code>next/dynamic</code> with the <code>ssr: false</code> option (note: <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading">Vercel recommends</a> using <code>React.lazy</code> and <code>Suspense</code> directly instead of <code>next/dynamic</code>:)</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>;

<span class="hljs-keyword">const</span> DynamicHeader = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/header'</span>), {
  ssr: <span class="hljs-literal">false</span>,
});
</code></pre>
<p>This enables Next.js to be a truly hybrid framework and it promotes the goal of Next, which is to statically render as much content as possible and only include what’s needed by the client.</p>
<p>What this means is that you need to think about how a client component will be rendered on the server. A way to test this is to disable JavaScript in your browser and see how the page renders. What you should see is that the page renders in its entirety, but interactive elements are disabled.</p>
<p>You will want to make sure that no layout shift is introduced when the element becomes interactive, so make sure the component renders well before JavaScript is enabled, either by rendering the content by default or by making use of skeletons.</p>
<h3 id="heading-choosing-rendering-at-component-level">Choosing Rendering at Component Level</h3>
<p>What is cool about this new approach is that you can you can interleave Server and Client Components in your application, and behind the scenes, React will seamlessly merge the work of both environments.</p>
<blockquote>
<p><em>React can render on the client and the server, and you can choose the rendering environment at the component level!</em></p>
</blockquote>
<p>In Next.js 13, all the components within the /app folder are server components by default. You will use the <code>"use client"</code> directive if you want to render Client Components.</p>
<p>In the example below, Counter is a Client Component, because it preserves local state and has event handlers for a button click. This component will have a <code>"use client"</code> directive placed on top of the component file, above the imports, to indicate that it is a Client Component.</p>
<blockquote>
<p>Once <code>"use client"</code> is defined in a file, all other modules imported into it, including child components, are considered part of the client bundle.</p>
</blockquote>
<p><em>Note</em>: This additional step could be confusing for developers and is part of the learning curve that comes with Next.js 13.</p>
<pre><code class="lang-typescript"><span class="hljs-string">'use client'</span>

<span class="hljs-comment">// Client Component, because it stores state and has the use client directive.</span>

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>)

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;p&gt;You clicked {count} times&lt;/p&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> setCount(count + <span class="hljs-number">1</span>)}&gt;Click me&lt;/button&gt;
    &lt;/div&gt;
  )
}
</code></pre>
<h3 id="heading-composing-client-and-server-components">Composing client and server components</h3>
<p>Next.js 13 offers an enhanced level of flexibility when it comes to composing your components. Server components can also render other server components and client components. On the other hand, client components can render other client components and can only render server components if they are passed in as a prop. This layered composition model allows for a high degree of interoperability and code reusability.</p>
<p>For instance, the following is not allowed in React:</p>
<pre><code class="lang-typescript"><span class="hljs-string">'use client'</span>;

<span class="hljs-comment">// ❌ You cannot import a Server Component into a Client Component</span>
<span class="hljs-keyword">import</span> MyServerComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'./MyServerComponent'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ClientComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      &lt;MyServerComponent /&gt;
    &lt;/&gt;
  );
}
</code></pre>
<p>Instead, you can pass a Server Component as a child or a prop to a Client Component as a workaround, as shown below.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ✅ You can pass a Server Component as a child or prop of a Client Component.</span>
<span class="hljs-keyword">import</span> ClientComponent <span class="hljs-keyword">from</span> <span class="hljs-string">"./ClientComponent"</span>;
<span class="hljs-keyword">import</span> ServerComponent <span class="hljs-keyword">from</span> <span class="hljs-string">"./ServerComponent"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;ClientComponent&gt;
      &lt;ServerComponent /&gt;
    &lt;/ClientComponent&gt;
  );
}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-string">'use client'</span>;

<span class="hljs-comment">// ✅ You can pass a Server Component as a child or prop of a Client Component.</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ClientComponent</span>(<span class="hljs-params">{children}</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      {children}
    &lt;/&gt;
  );
}
</code></pre>
<p>I get that the paragraph above is kind of mind-numbing. Here’s a nice diagram that Vercel folks created to help you visualize this concept better.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750587134390/b118d52e-711d-43b5-ba6f-0595c817c9ac.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-nextjs-13-rendering-modes">Next.js 13 Rendering Modes</h3>
<p>Next.js 13 introduces different render environments and modes, allowing you to choose the optimal rendering strategy for your app on a component-by-component basis.</p>
<p>Content is rendered in two distinct environments:</p>
<ul>
<li><p>Client side — Client Components are pre-rendered and cached on the server. JSON is generated for data used on client components and passed to React during Hydration.</p>
</li>
<li><p>Server side —Content is rendered on the server by React, and static HTML is generated. React uses static HTML to hydrate in the browser, requiring no additional JavaScript on the client.</p>
</li>
</ul>
<p>On the server, there are two different rendering modes that are used:</p>
<ul>
<li><p>Static — both client and server components are rendered as static HTML at build time. Static content can be <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/data-fetching/revalidating">revalidated</a>, allowing it to be updated on a page-by-page basis in order to keep dynamic data up-to-date with its sources. Statically generated content is easily cacheable and leads to improved performance, user experience, and search engine optimization.</p>
</li>
<li><p>Dynamic — both client and server components are rendered on the server when a request is made. The content is not cached.</p>
</li>
</ul>
<p>Previous versions of Next.js had different terminology that it used for these concepts. I’m including them below and showing how they relate to the new Next.js 13 terminology.</p>
<ul>
<li><p><strong>Static-site generation (SSG)</strong>: Static rendering mode</p>
</li>
<li><p><strong>Incremental Static Regeneration (ISR)</strong>: Static rendering mode with revalidation</p>
</li>
<li><p><strong>Server-side Rendering (SSR)</strong>: Dynamic rendering mode</p>
</li>
<li><p><strong>Client-side Rendering (CSR)</strong>: Client components</p>
</li>
</ul>
<p>Make sure to check out the Next.js documentation site on the <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/rendering#rendering-environments">topic</a>.</p>
<h3 id="heading-when-to-use-client-vs-server-components">When to Use Client vs. Server Components?</h3>
<p>You only need to mark components as “use client“ when they use client hooks such as <em>useState</em> or <em>useEffect</em>.</p>
<p>It’s best to leave components that do not depend on client hooks without the directive so that they can automatically be rendered as a Server Component when they aren’t imported by another Client Component.</p>
<p>This helps ensure the smallest amount of client-side JavaScript.</p>
<blockquote>
<p>The goal is to ship the smallest amount of client-side JavaScript.</p>
</blockquote>
<p><strong>Use Client Components when:</strong></p>
<ul>
<li><p>You use React hooks such as <em>useState</em>, <em>useEffect</em>, <em>useReducer,</em> etc*..*</p>
</li>
<li><p>There is interactivity within the component, with event listeners such as <em>onClick()</em>.</p>
</li>
<li><p>There are custom hooks that depend on state or effects.</p>
</li>
<li><p>Using React Class Components.</p>
</li>
</ul>
<p><strong>Use Server Components when:</strong></p>
<ul>
<li><p>You fetch data from the server API.</p>
</li>
<li><p>Sensitive information needs to be stored (tokens, API keys, etc.).</p>
</li>
<li><p>You need to access backend resources directly.</p>
</li>
<li><p>There are large dependencies.</p>
</li>
</ul>
<h3 id="heading-server-components-vs-ssr-whats-the-difference">Server Components Vs. SSR: What’s the Difference?</h3>
<p>The main difference between Server Components and SSR lies in the ‘when’ and ‘what.</p>
<p>SSR happens at the time of each page request. The server fetches data, generates the HTML, and then sends this HTML to the client. This process repeats with every request. SSR is great for pages with data that changes frequently, and it’s a fantastic boon for SEO.</p>
<blockquote>
<p><em>SSR is the rendering of an entire page (which is composed of several components) on the server; Server Component is executing an individual component on the server, generate a static HTML response, and send it to the client.</em></p>
</blockquote>
<p>On the other hand, Server Components run once at build time. They execute on the server, generate a static HTML response, and send this to the client. This process doesn’t repeat with every request. As such, Server Components are best for parts of your application that don’t change frequently, and they help in significantly reducing the amount of JavaScript shipped to the client.</p>
<h2 id="heading-streaming">Streaming</h2>
<p>Previously, the user might have had to wait for the complete page to generate. Now the server will transmit to the client small pieces of the UI as it is generated. It implies that the bigger piece won’t get in the way of the smaller ones. Of course, as of right now, just the app directory is supported for this feature, and it doesn’t seem that this will change.</p>
<p>This new feature won’t benefit individuals with a strong internet connection or speedy wifi as much as those with a weaker connection. There are more of them than you would have thought, in fact. It’s great that a faster site loading time will improve user experience.</p>
<h2 id="heading-server-actions-alpha">Server Actions (Alpha)</h2>
<p>Next.js 13.4 introduces Server Actions (currently in alpha), which brings a whole level of flexibility and power to your applications. Server Actions allow you to handle server-side logic, such as fetching data or interacting with APIs, directly in your application. This feature not only simplifies your application architecture but also enables you to create faster and more efficient applications.</p>
<p>For an in-depth look at Server Actions and how they are transforming the way we build applications, check out this article: <a target="_blank" href="https://medium.com/front-end-weekly/why-next-js-server-actions-are-game-changing-20025c9a3551">Why Next.js Server Actions are Game-Changing</a>.</p>
<h2 id="heading-turbopack-now-in-beta-and-more-feature-complete">Turbopack: Now in Beta and More Feature Complete</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750586134680/d7382087-b874-47a2-9e56-5503a89426b3.webp" alt class="image--center mx-auto" /></p>
<p>With the release of Next.js 13.4, Turbopack has moved into the beta phase, offering a more feature-complete and stable experience. Turbopack is Next.js’s new Rust-based bundle designed to speed up local iterations in development, and soon, production builds. Thanks to the community’s support in testing and reporting bugs, Turbopack has grown in adoption, paving the way for a significantly faster and more efficient development experience in the future.</p>
<h1 id="heading-nextjs-12">Next.js 12</h1>
<p>Next.js has announced at their Next.js conference that Next.js 12 is going to be one of the biggest releases ever. So in this section, let’s quickly look into what the new amazing features are that Next.js 12 has provided us with:</p>
<p>There are roughly 6 new features that Next.js 12 has brought out. Let’s look into all of them.</p>
<h2 id="heading-faster-builds">Faster Builds</h2>
<p>The new Next.js 12 ships with a new Rust compiler. This compiler takes advantage of native compilation. This translates into a much faster build and faster refresh time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754913411190/a0022910-90f6-4398-adbf-73792aff40c3.webp" alt class="image--center mx-auto" /></p>
<p>How does that work? <mark>The compiler is built on top of SWC, which stands for </mark> <code>Speedy Web Compiler</code>. It does consume Typescript/JavaScript and emits JavaScript code that can be executed on old browsers. It’s a Babel replacement. It’s about 20x faster than Babel on a single thread and up to 70x on a four-core benchmark.</p>
<p>This Rust compiler is now enabled by default. The improvement of the Vercel.com build is about 50% faster. It went from 3 minutes 41 seconds down to 1 minute and 58 seconds.</p>
<p>It is still not perfect because it might lack some compatibility with popular libraries like <code>styled-components</code> or <code>emotion</code> but that support will happen soon.</p>
<p>You can also use it to minify files by simply enabling it in the config. Here’s the code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// next.config.js</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  swcMinify: <span class="hljs-literal">true</span>
}
</code></pre>
<h2 id="heading-middleware">Middleware</h2>
<p>This is one of the most exciting features. At the moment, we have to choose between CDN or Server Side Rendering for building faster apps. When we build a dynamic page that we want to cache, we might use the latter.</p>
<p>Vercel’s new Edge functions feature makes this possible. It gives <mark>the benefits of static caching with the power of dynamic execution. </mark> Now we can run dynamic functions aka middleware, right before our CDN requests complete. All that with no cold start.</p>
<p>The Cloudflare and Amazon infrastructure have also implemented a similar feature not long ago. It is called <code>edge computing</code> or <code>Lamdba@Edge</code>. What is special about the Next.js version? It’s easy and integrates within the framework.</p>
<p>How to use it? By just creating a <code>_middleware</code> function in our pages directory and deploying it. There, we can do dynamic checks right at the CDN level. These middleware functions can be scoped and composed.</p>
<pre><code class="lang-typescript"># Execution order <span class="hljs-keyword">for</span> middleware composition
- /pages
  index.tsx
  - /profile
    _middleware.ts # will run first
    profile.tsx
    - /settings
      _middleware.ts # will run second
      _settings.tsx
</code></pre>
<p>What does a <code>_middleware.ts</code> file look like? Let’s see that through an example where we create a dummy authentication middleware.</p>
<p>In the code above, we can check if the request contains a valid JWT and otherwise return an error response.</p>
<p>What are the most common use cases for using middleware?</p>
<ul>
<li><p>User Authentication</p>
</li>
<li><p>Bot protection</p>
</li>
<li><p>Redirects and rewrites</p>
</li>
<li><p>Handling unsupported browsers</p>
</li>
<li><p>Service-side analytics</p>
</li>
<li><p>Advanced 18n routing</p>
</li>
<li><p>Logging</p>
</li>
</ul>
<h2 id="heading-url-imports">URL Imports</h2>
<p>The Next.js team has been working for a while to support ES modules. It was flagged as experimental in the previous version. In this new version, they are natively supported.</p>
<p>What does that mean? The URL imports can be built on top of those.</p>
<p>Why is this feature cool? We can now import directly tooling from the CDN without any extra builds or installs. We will be able to import those from the wire rather than having to build them locally.</p>
<p>You can now use cool CDN projects like Skypack in your Next.js app. It’s a package delivery network over CDN. It creates ready-for-production tools without the hassle of compiling and bundling them. It scans NPM and builds executable ES module packages that you can import from your browser.</p>
<p>How to enable this feature? The URL has to be specified in the <code>next.config.js</code> file. You need to only enable domains that you trust.</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  experimental: {
    urlImports: [<span class="hljs-string">'https://cdn.skypack.dev'</span>],
  },
}
</code></pre>
<p>As you can see from the config, this URL import feature is still in the experimental phase.</p>
<p>What does the Next.js workflow look like?</p>
<ul>
<li><p>on <code>next dev</code> the will amend the download and add the file in a <code>next.lock</code> file</p>
</li>
<li><p>on <code>next build</code> the engine will look up the generated <code>next.lock</code> file.</p>
</li>
</ul>
<p>Let’s see a bit of code in action:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// next.config.js</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  reactStrictMode: <span class="hljs-literal">true</span>,
  experimental: {
    urlImports: [<span class="hljs-string">'https://cdn.skypack.dev'</span>],
  },
}

<span class="hljs-comment">// pages/index.js</span>
<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'../styles/Home.module.css'</span>
<span class="hljs-keyword">import</span> confetti <span class="hljs-keyword">from</span> <span class="hljs-string">'https://cdn.skypack.dev/canvas-confetti'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div className={styles.container}&gt;
      &lt;main className={styles.main}&gt;
        &lt;h1 className={styles.title}&gt;
          Welcome to &lt;a href=<span class="hljs-string">"https://nextjs.org"</span>&gt;Next.js!&lt;/a&gt;
        &lt;/h1&gt;
        &lt;button onClick={confetti}&gt;
          Throw Confetti
        &lt;/button&gt;
      &lt;/main&gt;
    &lt;/div&gt;
  )
}
</code></pre>
<h2 id="heading-support-for-react-18-on-the-server-side">Support for React 18 on the server-side</h2>
<p>The React 18 version is coming soon, and after a boring release of React 17, it’s mainly focused on concurrency.</p>
<p>The Next.js framework is jumping early and anticipating some of React’s most-awaited features. Naturally, all these new features will also be under an experimental config flag.</p>
<h3 id="heading-html-server-side-streaming">HTML Server Side Streaming</h3>
<p>One of the coolest React 18 features is the built-in support of server-side Suspend and streaming of HTML parts of your React application. You are no longer required to load all or nothing. You can progressively ship HTML to the browser.</p>
<p>The Next.js framework supports that and provides abstractions around all those mechanisms. For dynamically importing modules, you can use its <code>next/dynamic</code> utility.</p>
<h3 id="heading-react-server-side-components">React server-side components</h3>
<p>The new React Server Component feature does simplify the SSR development and logic. They are always rendered on the server and streamed to the client. This reduces the need for handling different rendering scenarios. The usage of <code>getServerSideProps</code> and <code>getStaticProps</code> is not needed anymore. The shift the computation from the client to the server.</p>
<p>Those are big improvements; however, they still have some limitations:</p>
<ul>
<li><p>They are stateless.</p>
</li>
<li><p>They can’t use lifecycle methods like <code>useState</code> or <code>useEffect</code>.</p>
</li>
<li><p>They can’t make usage of browser-only APIs.</p>
</li>
</ul>
<p><strong>Usage</strong></p>
<p>How do you opt in to all these new React 18 goodies?</p>
<p><strong>1.</strong> First, you need to install React 18 Alpha using the following code:</p>
<pre><code class="lang-typescript">npm install next<span class="hljs-meta">@latest</span> react<span class="hljs-meta">@alpha</span> react-dom<span class="hljs-meta">@alpha</span>
</code></pre>
<p><strong>2.</strong> Enable the experimental concurrent features in Next.js configuration, as shown below:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// next.config.js</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  experimental: {
    concurrentFeatures: <span class="hljs-literal">true</span>,
    serverComponents: <span class="hljs-literal">true</span>,
  },
}
</code></pre>
<p>With that, you are good to go.</p>
<h2 id="heading-on-demand-incremental-static-regeneration-stable">On-demand Incremental Static Regeneration (Stable)</h2>
<p>How many times can you redeploy in a workday? On-demand Incremental Static Regeneration (ISR) allows you to update content on your site without the need to redeploy. This makes it easy to update your site immediately when your site changes in your headless CMS or commerce platform. This is one of the most requested features from the community, and we are excited that it’s now stable.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755085180572/d653e25f-a01a-42a2-bc64-4c683094287d.webp" alt class="image--center mx-auto" /></p>
<p>Incremental Static Regeneration (ISR) works for any providers supporting the <a target="_blank" href="https://nextjs.org/docs/deployment#nextjs-build-api">Next.js Build API</a> (next build). When deployed to Vercel, on-demand revalidation propagates globally in ~300ms when pushing pages to the edge.</p>
<h2 id="heading-smaller-images-using-avif">Smaller Images Using Avif</h2>
<p>The Built-in Image Optimization API now supports AVIF images, enabling 20% smaller images compared to WebP.</p>
<p>AVIF images can take longer to optimize compared to WebP, so we're making this feature opt-in using the new <code>images.formats</code> property in <code>next.config.js</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {  images: {    formats: [<span class="hljs-string">'image/avif'</span>, <span class="hljs-string">'image/webp'</span>],  },};
</code></pre>
<p>This list of formats is used to determine the optimized image format on demand using the request’s Accept header:</p>
<p>Since AVIF is first, it will be served if the <a target="_blank" href="https://caniuse.com/avif">browser supports AVIF</a>. If not, WebP will be served if the <a target="_blank" href="https://caniuse.com/webp">browser supports WebP</a>. If neither format is supported, the original image format will be served.</p>
<h2 id="heading-output-file-tracing">Output File Tracing</h2>
<p>In Next.js 8, we introduced the <code>target</code> option. This allowed for outputting Next.js pages as standalone JavaScript bundles by bundling all dependencies using webpack during the build. We quickly realized this wasn't ideal and instead created <code>@vercel/nft</code>. <code>@vercel/nft</code> has been used for over 2 years on all deployments on the Vercel platform.</p>
<p>Now, we're bringing these improvements directly into the Next.js framework by default, <strong>for all deployment platforms</strong>, providing a significantly improved approach over the <code>target</code> option.</p>
<p>Next.js 12 automatically traces which files are needed by each page and API route using <code>@vercel/nft</code>, and outputs these trace results next to the <code>next build</code> output, allowing integrators to leverage the traces Next.js provides automatically.</p>
<p>These changes also optimize applications deployed using tools like Docker through <code>next start</code>. By leveraging <code>@vercel/nft</code>, we will be able to make the Next.js output standalone in the future. No dependencies will be required to be installed to run the application, massively reducing the Docker image size.</p>
<p>Bringing <code>@vercel/nft</code> into Next.js supersedes the <code>target</code> approach, making <code>target</code> deprecated in Next.js 12. <a target="_blank" href="https://nextjs.org/docs/pages/api-reference/next-config-js/output">Check out the documentation</a> for more info.</p>
<h2 id="heading-bot-aware-isr-fallback">Bot Aware ISR Fallback</h2>
<p>Currently, <a target="_blank" href="https://vercel.com/docs/concepts/incremental-static-regeneration/overview">Incremental Static Regeneration (ISR)</a> with fallback: true renders a fallback state before rendering the page content on the first request to a page that was not generated yet. To block the page from loading (server-rendering), you would need to use fallback: block.</p>
<p>In Next.js 12, <a target="_blank" href="https://nextjs.org/learn/seo/introduction-to-seo/webcrawlers">web crawlers</a> will automatically server-render ISR pages using fallback: true, while still serving the previous behavior of the fallback state to non-crawler User-Agent. This prevents crawlers from indexing loading states.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://medium.com/coding-beauty/the-new-next-js-15-changes-everything-cec14aaa50b3">https://medium.com/coding-beauty/the-new-next-js-15-changes-everything-cec14aaa50b3</a></p>
<p><a target="_blank" href="https://medium.com/@mitali_shah/why-is-next-js-15-revolutionizing-web-app-development-8164875d6f0d">https://medium.com/@mitali_shah/why-is-next-js-15-revolutionizing-web-app-development-8164875d6f0d</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/top-7-features-in-next-js-15-that-will-supercharge-your-web-apps-0c02bce2b51c">https://javascript.plainenglish.io/top-7-features-in-next-js-15-that-will-supercharge-your-web-apps-0c02bce2b51c</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/server-actions-streaming-and-more-the-full-power-of-next-js-15-bbfbe16cbecb">https://javascript.plainenglish.io/server-actions-streaming-and-more-the-full-power-of-next-js-15-bbfbe16cbecb</a></p>
<p><a target="_blank" href="https://medium.com/@imvinojanv/next-js-14-arrives-turbocharging-react-development-with-new-features-and-enhanced-performance-e961ff122915">https://medium.com/@imvinojanv/next-js-14-arrives-turbocharging-react-development-with-new-features-and-enhanced-performance-e961ff122915</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/4-major-features-in-next-js-14-3e897f391068">https://javascript.plainenglish.io/4-major-features-in-next-js-14-3e897f391068</a></p>
<p><a target="_blank" href="https://focusreactive.com/breaking-down-next-js-14/">https://focusreactive.com/breaking-down-next-js-14/</a></p>
<p><a target="_blank" href="https://medium.com/@Apiumhub/whats-new-in-next-js-14-and-how-does-it-achieve-to-be-so-fast-apiumhub-faa6b512c153">https://medium.com/@Apiumhub/whats-new-in-next-js-14-and-how-does-it-achieve-to-be-so-fast-apiumhub-faa6b512c153</a></p>
<p><a target="_blank" href="https://github.com/reactjs/rfcs/pull/227">http</a><a target="_blank" href="https://blog.bitsrc.io/next-js-13-4-is-finally-here-and-its-awesome-e9f5b27bccda">s://blog.bitsrc.io/next-js-13-4-is-finally-here-and-its-awesome-e9f5b27bccda</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/a-complete-guide-to-the-routing-system-in-next-js-13-with-simple-explanations-and-code-examples-74dce5042f83">https://levelup.gitconnected.com/a-complete-guide-to-the-routing-system-in-next-js-13-with-simple-explanations-and-code-examples-74dce5042f83</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/8-things-you-should-know-about-next-js-13-969291f168ec">https://medium.com/better-programming/8-things-you-should-know-about-next-js-13-969291f168ec</a></p>
<p><a target="_blank" href="https://adhithiravi.medium.com/the-yin-and-yang-of-next-js-13-understanding-server-components-and-server-side-rendering-6a9b774c3b06">https://adhithiravi.medium.com/the-yin-and-yang-of-next-js-13-understanding-server-components-and-server-side-rendering-6a9b774c3b06</a></p>
<p><a target="_blank" href="https://adhithiravi.medium.com/what-are-server-components-and-client-components-in-react-18-and-next-js-13-6f869c0c66b0">https://adhithiravi.medium.com/what-are-server-components-and-client-components-in-react-18-and-next-js-13-6f869c0c66b0</a></p>
<p><a target="_blank" href="https://medium.com/frontendweb/how-to-understand-and-use-the-uselinkstatus-hook-in-next-js-applications-7ddd5aad6924">https://medium.com/frontendweb/how-to-understand-and-use-the-uselinkstatus-hook-in-next-js-applications-7ddd5aad6924</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/5-new-killer-features-of-next-js-12-dfd1d766b539">https://medium.com/better-programming/5-new-killer-features-of-next-js-12-dfd1d766b539</a></p>
<p><a target="_blank" href="https://medium.com/@badcaptain0001/next-js-16-is-here-a-major-step-forward-for-performance-dx-full-stack-architecture-77aa0bcb91f7">https://medium.com/@badcaptain0001/next-js-16-is-here-a-major-step-forward-for-performance-dx-full-stack-architecture-77aa0bcb91f7</a></p>
]]></content:encoded></item><item><title><![CDATA[Bundlers Handbook]]></title><description><![CDATA[Bundlers
What is the JavaScript bundler anyway?
A tool that people struggle with for hours just to get a basic web app set up. A thing that you use when you want to bootstrap your React project? Something that your company uses, or that your colleagu...]]></description><link>https://blog.tuanhadev.tech/bundlers-handbook</link><guid isPermaLink="true">https://blog.tuanhadev.tech/bundlers-handbook</guid><category><![CDATA[bundlers]]></category><category><![CDATA[webpack]]></category><category><![CDATA[tree shaking]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Mon, 16 Jun 2025 10:36:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/B6yDtYs2IgY/upload/baa7e2366ec6b2eefa95ef655391d98d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-bundlers">Bundlers</h1>
<p><strong>What is the JavaScript bundler anyway?</strong></p>
<p>A tool that people struggle with for hours just to get a basic web app set up. A thing that you use when you want to bootstrap your React project? Something that your company uses, or that your colleagues/seniors have configured already? Which is apparently supposed to optimize your final JS build.</p>
<p>Whether you are starting your web development journey or have already used a bunch of bundlers before, you may have these questions at some point in time. I certainly did.</p>
<p>To answer the above question, <mark>a module bundler provides a method for arranging and merging multiple JavaScript files into a unified single file. Using a JavaScript bundler becomes necessary when your project outgrows a single file or when dealing with libraries with numerous dependencies. As a result, the end-user’s browser and client don’t have to fetch numerous files individually.</mark></p>
<h2 id="heading-why-do-we-need-a-javascript-bundler">Why do we need a JavaScript bundler?</h2>
<p>JavaScript bundlers are a tool that helps in optimizing the delivery of JavaScript files in web applications. The following are the key benefits of using a bundler.</p>
<ul>
<li><p><strong>Merging, Splitting, and Post-processing on Modules</strong>: While working with vanilla JavaScript or any corresponding modern JavaScript framework, it’s better to split the code into multiple files for the development journey. The concept of JavaScript bundlers is a decade old now. A decade ago, for browsers to access a single file through HTTP1 protocol was a heavy operation. So, it’s better to combine all the code into one file and then make a single HTTP request. But most browsers have improved a lot since then and are now using the HTTP2 protocol for sending network requests that show no bottleneck in sending multiple requests to access files. Instead, we have started to first compile and then split the codebase to load the minimum required sources on the requested route through bundlers. We have also started to remove the unused code (<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking">tree sharking</a>) and blank/while spaces among the combined files to minimize the requested resources (<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/minification">modification</a>)</p>
</li>
<li><p><strong>Solving the problem of cyclic dependencies:</strong> Without bundlers, one needs to take care of the import order of the JavaScript files to avoid the “not defined“ errors. Check out this <a target="_blank" href="https://github.com/mozilla/releases-comm-central/blob/master/mail/components/addrbook/content/abSearchDialog.xhtml#L34">file</a>. Developers need to take care of the import order of script tags by themselves, which is error-prone. Bundlers can traverse through all the required files and decide the loading order.</p>
</li>
<li><p><strong>Anchoring transpilation and pre-processing on modules</strong>: Nowadays, JavaScript has added some modern rules to improve the development journey. But modern browsers do not support these features yet, so one needs translators (which are generally called transpilers) to convert the modern JavaScript into the JavaScript that the browser can understand. Bundlers help in this process, where it first takes the help of the transpiler module to translate the files and then combine them for the browser to load directly.</p>
</li>
</ul>
<p>Modern JavaScript bundlers can be imagined as <strong>compilers</strong> that convert all the <strong>development-friendly code</strong> into an <strong>optimized browser-readable format</strong>.</p>
<h2 id="heading-behind-the-scenes-of-crafted-front-end-code-rendering-in-your-user-browser">Behind the Scenes of Crafted Front-end Code Rendering in your User Browser</h2>
<p>Ever wondered what happens behind the scenes when your code goes from your machine to the user’s browser? Well, let’s dive into it.</p>
<p>Meet our unsung hero: the bundler. It’s like the backstage manager, taking all your project files, doing some magic to optimize them, and then packing them up for a smooth delivery to web browsers. The result? A snappier and more responsive web app.</p>
<p>So, grab your coding beverage of choice, let’s break it down this journey step by step. We are about to uncover the nitty-gritty details of how your frontend code turns into that awesome experience</p>
<ol>
<li><strong>Input Files:</strong></li>
</ol>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*ud1bAduqoE18HMRwC9l3cw.png" alt /></p>
<p>A bundler starts with a set of input files, which are typically your project’s source code and assets, such as JavaScript files, CSS files, images, and more.</p>
<ol start="2">
<li><strong>Dependency Resolution:</strong></li>
</ol>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*J__YFTnZ5G4Y-tdUP5ZT1Q.png" alt /></p>
<p>The bundler analyzes your source code to identify dependencies. Dependencies are other files or modules that your code relies on, like importing JavaScript modules or CSS files.</p>
<ol start="3">
<li><strong>Code Transformation</strong></li>
</ol>
<p>Before bundling, the bundler may apply transformations to your code. For example, it might transpile modern JavaScript (ES6+) into older versions for broader browser compatibility, or it might process CSS preprocessor syntax like SASS or LESS into standard CSS.</p>
<ol start="4">
<li><strong>Bundling</strong></li>
</ol>
<p>The bundler combines all the input files, including their dependencies, into one or more modules. Each bundle is a single, optimized file containing the code and assets for your application.</p>
<ol start="5">
<li><strong>Optimization</strong></li>
</ol>
<p>During bundling, the bundler performs various optimizations, such as removing whitespace and comments, minifying code (reducing variable names to shorter forms), and eliminating dead code (code that’s never used). Some bundlers support code splitting, which means breaking the bundled code into smaller parts or chunks. These chunks can be loaded on demand when needed, reducing initial loading times. Bundlers can also handle assets like images and fonts, optimizing and providing them as part of the bundle or as separate files.</p>
<ol start="6">
<li><strong>Development Server (optional)</strong></li>
</ol>
<p>During development, bundlers often include a development server. This server serves your project locally, automatically rebuilds the bundle when you make a change, and may offer features like hot module replacement (HMR) for instant code updates without a full page refresh.</p>
<ol start="7">
<li><strong>Output Files</strong></li>
</ol>
<p>The result of bundling is one or more output files, typically named something like “bundle.js“ for JavaScript or “bundle.css “ for CSS. These files are optimized and ready for deployment. <a target="_blank" href="https://www.youtube.com/watch?v=MxBCPc7bQvM">Here’s a useful link to have hands-on knowledge of how to analyze your JavaScript bundle</a>.</p>
<ol start="8">
<li><strong>Deployment</strong></li>
</ol>
<p>The final bundled files, along with your HTML and other assets, are deployed to a web server or a hosting service to make your application accessible to everyone</p>
<ol start="9">
<li><strong>Loading in the Browser</strong></li>
</ol>
<p>In the user’s browser, when they access your web application, the bundled JavaScript and CSS files are loaded, and the code is executed.</p>
<ol start="10">
<li><strong>Rendering the Web Page</strong></li>
</ol>
<p>The bundled JavaScript code initializes your application, interacts with the DOM, and renders a web page according to your application’s logic and structure.</p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/javascript-es-modules-and-module-bundlers/">https://www.freecodecamp.org/news/javascript-es-modules-and-module-bundlers/</a></p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=MUSoj2JcD4A">https://www.youtube.com/watch?v=MUSoj2JcD4A</a></p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=5IG4UmULyoA">https://www.youtube.com/watch?v=5IG4UmULyoA</a></p>
<h2 id="heading-popular-react-bundle-tools">Popular React Bundle Tools</h2>
<h3 id="heading-rollup-vs-parcel-vs-webpack-which-is-the-best-bundle">Rollup vs. Parcel vs. Webpack: Which is the best bundle?</h3>
<p>Recently, I was publishing a library to npm, and I thought of experimenting with the bundler. I was going to package my code. While <a target="_blank" href="https://webpack.js.org/">Webpack</a> has always been my standard choice, I decided to put it up against two other popular bundlers — <a target="_blank" href="https://rollupjs.org/guide/en/">Rollup</a> and <a target="_blank" href="https://parceljs.org/">Parcel</a>.</p>
<p>From those coming from a non-JavaScript background, a bundler is a tool that recursively follows all imports from the entry point of your app and bundles them up into a single file. Bundlers can also minify your files by removing unnecessary white spaces, new lines, comments, and block delimiters without affecting their functionality.</p>
<p>Let’s try to understand this through a simple code snippet:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">var</span> test = [];
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">100</span>; i++) {
  test[i] = i;
}
</code></pre>
<p>We just created an array called test and initialised its members up to 100. The minified version of this code will look somewhat like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> a=[i=<span class="hljs-number">0</span>];++i&lt;<span class="hljs-number">20</span>;a[i]=i);
</code></pre>
<p>Fewer characters and lines. You might say the code isn’t readable, but who cares? You bundle your code once it’s ready, and minified code is easy to fetch and interpret for the browser.</p>
<p>It must be now easy for you to guess the importance of a bundler, right?</p>
<p>Suppose your code is not bundled and hosted as a package multiple times on a server. For the import of each of these files to make your code run, the browser has to send a separate HTTP request to the server. The efficiency of this transmission is directly proportional to the number and the size of the files being requested. In the case of large apps such as Facebook, this can lead to disastrous performance and UX.</p>
<p>However, the performance of the app substantially improves with a bundler on board, as now the browser only has to request a single file to display your app to the user. Moreover, fetching a minified file weighing a few KBs is faster than the actual file, which might run into MBs, resulting in improved load time in the app.</p>
<p><strong>Why install bundlers when we can do it on our own?</strong></p>
<p>Sure, you can, but when working with huge codebases, minifying an app manually isn’t a scalable solution. Let the bundler do it for you.</p>
<p>Making the right choice of a bundler from the many available can be life-changing for your app, depending on the use case. Coming back to the experiment I was talking about in the beginning. I thought of sharing with you my findings on how Webpack, Rollup, and Parcel fared on some important requirements a developer would have.</p>
<ol>
<li><strong>Configuration of the bundler</strong></li>
</ol>
<p>Parcel wins here because it doesn’t require a config file at all. Just install Parcel and run parcel build, and it will do everything for you out of the box.</p>
<p>Webpack and Rollup both require a config file specifying entry, output, loaders, plugins, transformations, etc. However, there’s a slight difference.</p>
<ul>
<li><p>Rollup has node polyfills for import/export, but Webpack doesn’t.</p>
</li>
<li><p>Rollup has support for relative paths in config, but webpack doesn’t — which is why you use <code>path.resolve</code> or <code>path.join</code></p>
</li>
</ul>
<p>Webpack config can get complex, but it provides extensive support for third-party imports, images, CSS preprocessor, and whatnot.</p>
<p>I had a hard time using Rollup for bundling my app that used axios, a very commonly used library for making HTTP requests — not just axios, but for other third-party integrations too. I had to research a lot and try installing many Rollup plugins before attaining victory, at the cost of dropping some imports.</p>
<ol start="2">
<li><strong>Dead code elimination</strong></li>
</ol>
<p><mark>Dead code elimination, or </mark> <em><mark>Tree shaking</mark></em><mark>, as it’s often called, is very important to achieve the optimum bundle size and hence app performance.</mark></p>
<p><strong>Parcel emerged as the winner</strong> here. Parcel supports tree shaking for both ES6 and CommonJS modules. This is revolutionary since most of the code in libraries on npm still uses <a target="_blank" href="https://www.npmjs.com/search?q=commonjs">CommonJS</a>.</p>
<p>Most of the work Parcel does when tree shaking is also done in parallel through multicore processing using numerous worker processes, and is also cached on the file system. This means that it builds are still fast, and rebuilds are like blazing fast.</p>
<p><strong>Roll comes second in the race</strong>. Right out of the box, it statically analyzes the code you are importing and will exclude anything that isn’t actually used. This saves you from writing more lines in your config file, adding extra dependencies, and bloating the size of your app.</p>
<p>Webpack requires some manual effort to enable tree-shaking:</p>
<ul>
<li><p>Use ES6 syntax (i.e. <code>import</code> and <code>export</code>).</p>
</li>
<li><p>Set the <code>SideEffects</code> flag in your <code>package.json</code>.</p>
</li>
<li><p>Include a minifier that supports dead code removal (eg: <code>UglifyJSPlugin</code>).</p>
</li>
</ul>
<p>Rollup and Webpack have focused more on tree shaking for ES6 since it is much easier to statically analyze, but in order to truly make a big impact, we need to analyze CommonJS dependencies as well, for which they both require plugins to be imported.</p>
<p>However, given the fact that JavaScript is dynamic, almost every construct in the language can be altered at runtime in impossible to predict ways.</p>
<p>Practically, this means that an entity such as a class, which is imported as one reference, can be statically analyzed to remove members (both static and instance) that are not used. So, rather than relying on the bundler to do it for you, it will be a good practice to visualize your components before your code and analyze them afterwards to get the best results.</p>
<ol start="3">
<li><strong>Code splitting</strong></li>
</ol>
<p>As your app grows, your bundle size will grow too, more so with third-party imports. The load time of your app is directly proportional to its bundle size.</p>
<p>Code splitting helps the browser lazy-load just the things that are needed to get the app running, dramatically improving the performance and UX.</p>
<p><strong>Webpack emerges as the winner in this aspect</strong>, with minimal work and faster load time. It provides three approaches to enable code splitting available in Webpack.</p>
<ul>
<li><p><strong>Define entry point</strong>s - Manually split code using <a target="_blank" href="https://webpack.js.org/configuration/entry-context"><code>entry</code></a> configuration.</p>
</li>
<li><p><strong>Use the</strong> <a target="_blank" href="https://webpack.js.org/plugins/commons-chunk-plugin">commonsChunkPlugin</a> to de-dupe and split chunks</p>
</li>
<li><p><strong>Dynamic imports</strong> - use inline function calls within modules</p>
</li>
</ul>
<p>During code splitting by Rollup, your code splitting chunks themselves are standard ES modules that use the browser’s built-in loader without any additional overhead, while still getting the full benefit of Rollup’s tree-shaking feature.</p>
<p>Parcel supports zero-configuration code splitting. Here, code splitting is controlled by the use of the dynamic <code>import()</code> <a target="_blank" href="https://github.com/tc39/proposal-dynamic-import">function syntax proposal</a>, which works like a normal <code>import</code> statement or <code>require</code> function, but returns a <code>Promise</code>. This means that the module is loaded asynchronously.</p>
<p>It was tempting to favour Rollup and Parcel over Webpack for code splitting, but both of them have only recently introduced this feature, and some issues have also been reported. So, it’s safe to stick with the good old webpack.</p>
<p>One compelling fact I noticed was that for the same code with code splitting enabled, the build time was the least with webpack, followed by Rollup, and lastly, Parcel.</p>
<ol start="4">
<li><strong>Live reload</strong></li>
</ol>
<p>During development, it’s great if your app gets updated with the fresh code that you write, instead of manually refreshing it to see the changes. A bundler with live reload capability does that refreshing for you.</p>
<p>Bundlers provide you with a runtime environment in addition to other utilities essential for debugging and development, in the form of a development server.</p>
<p>Parcel has been very thoughtful by having a development server built in, which will automatically rebuild your app as you change files. But there are issues associated with it when using HTTP logging, Hooks, and middleware.</p>
<p>When using Rollup, we need to install and configure<code>rollup-plugin-serve</code>, which will provide us with live reload functionality. However, it needs another plugin, <code>rollup-plugin-livereload</code>, to work. That means it’s not an independent plugin and comes with an extra dependency to run.</p>
<p>With Webpack, you just need to add one plugin, <code>called webpack-dev-server</code>, which provides a simple development server with live reload functionality turned on by default. What’s better? You can use Hooks to do something after the dev server is up and running, add middleware, and also specify the file to serve when we run the dev server. <strong>The customisability of Webpack trumps Rollup and Parcel</strong>.</p>
<ol start="5">
<li><strong>Hot module replacement</strong></li>
</ol>
<p>Hot module replacement (HRM) improves the development experience by automatically updating modules in the browser at runtime without needing a whole page refresh. You can retain the application state as you make small changes in your code.</p>
<p>You might ask how HRM is different from live reload.</p>
<p>Well, live reloading reloads the entire app when a file changes. For example, if you were five levels deep into your app navigation and saved a change, live reloading would restart the app altogether and load it back to the landing/initial route.</p>
<p>Hot reloading, on the other hand, only refreshes the files that were changed while still maintaining the state of the app. For example, if you were 5 levels deep into your app navigation and saved a CSS change, the state would not change: You would still be on the same page, but the new styles would be visible.</p>
<p>Webpack has its own web server, called the <code>webpack-dev-server</code>, through which it supports HMR. It can be used in development as a live reload replacement.</p>
<p>Rollup released a plugin <code>rollup-plugin-hotreload</code> last month to support hot reload.</p>
<p>As this capability is fairly new in bundlers like Rollup and Parcel, I still choose Webpack as the safe bet for I don’t want to run into avoidable issues during development.</p>
<ol start="6">
<li><strong>Module transformers.</strong></li>
</ol>
<p>Bundlers generally know only how to read JS files. Transformers are essentially teachers who teach the bundler how to process files other than JS and add them to your app’s dependency graph and module.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:600/1*fQYPJhmQuHA93GWcChKBTw.png" alt class="image--center mx-auto" /></p>
<p>For example, in the image above, you can see a webpack config having an instruction on how to read CSS between lines 13 to 15. It basically says, “Hey Webpack, whenever you encounter a file that is resolved as <code>.css</code>, use <code>css-loader</code> imported above to read it and export it as a string“. Similarly, an HTML loader will tell Webpack how to read the <code>.HTML</code> files it encounters in your app and export them as strings in your bundler.</p>
<p>Parcel handles the transformation process very smartly. Unlike Rollup and Webpack, which need you to specify file types to transform, install, and configure, and plugins to transform them, Parcel provides built-in support for many common transforms and transpilers.</p>
<p>Parcel automatically runs the appropriate transformer when it finds a configuration file such as<code>.babelrc</code>, <code>.postcssrc</code>, <code>.posthtml</code>, etc., in a module. In addition to any transforms specified in .babelrc, Parcel always uses Babel on all modules to compile modern JavaScript into a form supported by browsers.</p>
<p><strong>✅ In a nutshell</strong></p>
<ul>
<li><p>Building a library with minimal third-party imports? Use Rollup</p>
</li>
<li><p>Building a basic app and want to get it up and running quickly? Use Parcel.</p>
</li>
<li><p>Building a complex app with lots of third-party integrations? Need good code splitting, use of static assets, and CommonJS dependencies? Use Webpack.</p>
</li>
</ul>
<p>Personally, I will continue to prefer Webpack for my projects. One might argue that Parcel, in many cases, offers built-in configurations that might provide ease of development, but it’s difficult to overlook the extensive support and customizability that Webpack provides.</p>
<h1 id="heading-webpack">Webpack</h1>
<p><a target="_blank" href="https://webpack.js.org/">Webpack</a> is a commonly used library among modern frontend-based applications. It is one of the popular JavaScript bundlers. It’s now a decade-old and battle-tested library. Many of full full-fledged frontend frameworks like <a target="_blank" href="https://nextjs.org/">NextJs</a> and <a target="_blank" href="https://www.gatsbyjs.com/">Gatsby</a> use Webpack for bundling and compilation purposes by default. If you ask someone what Webpack is, they will answer that it’s a JavaScript bundler. If you go a bit more and ask why we need a JavaScript bundler and how it works, only the curious might be able to answer satisfactorily. It isn’t anyone's fault, modern frontend libraries are packed in a way that you don’t need to worry about what happens under the hood. If we take an example of a ReactJS application configured through the <a target="_blank" href="https://reactjs.org/docs/create-a-new-react-app.html">create-react-app</a> library, it takes care of the configuration of bundlers and transpilers. Developers can immediately start building an application with the knowledge of <a target="_blank" href="https://reactjs.org/">ReactJS</a>. If one wants to master the art of building fast and performant frontend applications, one needs to have a clear mental model of the functioning of all these libraries.</p>
<h2 id="heading-how-does-webpack-work">How does Webpack work?</h2>
<p>Webpack is an event-driven, plugin-based compiler. That means Webpack has a life cycle for bundling the files, and each life-cycle step can be imagined as an event. We can add a plugin that will listen to these different events and act accordingly. The default functionalities can also be inserted through plugins, i.e., there will be some default plugins handling some core functionalities.</p>
<p>Let’s say the life cycle has these 5 methods:</p>
<blockquote>
<p><em>compilation-start → resolve → parse → bundle → compilation-end</em></p>
</blockquote>
<p>The plugin can be integrated to listen to these events and perform the operation on the source code files. There will be some default plugins integrated to perform the core functionality.</p>
<p>Any plugin-based architecture can be designed similarly; it has a life cycle for any particular feature, and custom event handlers (which can be imagined as plugins) can be added to act upon at different steps of the life cycle.</p>
<p>Let’s not go through the Webpack life cycle:</p>
<h2 id="heading-what-happens-under-the-hood-in-webpack">What happens under the hood in Webpack?</h2>
<p>Let’s understand some keywords and then connect them to form a whole story.</p>
<ul>
<li><p><strong>Compiler</strong>: Just like a normal compiler, it will be a starting and stopping point in the webpack life cycle. It can be imagined as a central dispatcher of events.</p>
</li>
<li><p><strong>Compilation AKA The Dependency Graph</strong>: It’s like the brain. Through this, Webpack understands which sources you are using in your codebase. It contains the dependency graph traversal algorithm. It is created by the compiler.</p>
</li>
<li><p><strong>Resolver</strong>: It converts the partial path into the absolute path. This will be used to check if some files exist, and if it does, give us some information.</p>
</li>
<li><p><strong>Module Factory</strong>: Takes successfully resolved requests by the resolver and creates a module object with source files and some information received by the resolver.</p>
</li>
<li><p><strong>Parser</strong>: Takes a module object and turns it into an AST (a tree representation of the source code) to parse. Find all queries and imports and make a tree to parse for bundling.</p>
</li>
<li><p><strong>Templates</strong>: It is used for data binding for the dependency graph. It binds the tree object into the actual code in the module.</p>
</li>
</ul>
<p>Now, let’s connect these dots:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748520856592/dcbcb11b-5cde-4d0f-8c0c-165680623d65.png" alt class="image--center mx-auto" /></p>
<p>First of all, Webpack will look at the configuration file and look for the entry point mentioned. The <a target="_blank" href="https://github.com/webpack/webpack/blob/main/lib/Compiler.js">compiler</a> will start the <a target="_blank" href="https://github.com/webpack/webpack/blob/main/lib/Compilation.js">compilation</a> from that file. A relative path will be sent to the <a target="_blank" href="https://github.com/webpack/webpack/blob/main/lib/ResolverFactory.js">resolver</a>. The resolver will convert the relative path to the absolute path. The request will go to the module factory. <a target="_blank" href="https://github.com/webpack/webpack/blob/main/lib/ModuleFactory.js">The module factory</a> will create a module object with some more information like the type of the file, size, absolute path, assigned id, etc.</p>
<p>Now, according to the file type mentioned in the module object, the compiler will look for the transpilers to convert the code into a browser-readable format. After converting the code, the <a target="_blank" href="https://github.com/webpack/webpack/blob/main/lib/Parser.js">parser</a> will parse the file and look for the ‘require‘ or ‘imports‘ statements and update the object with the dependency information like below:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// example module object</span>
{
  id: <span class="hljs-number">0</span>,
  absolutePath: <span class="hljs-string">'/path'</span>,
  fileType: <span class="hljs-string">'.jsx'</span>,
  dependency: [{ id1, relativePath }, { id2, relativePath }]
  <span class="hljs-comment">// some more information</span>
}
</code></pre>
<p>The compiler will parse the file recursively in this manner to finally form a complete <a target="_blank" href="https://github.com/webpack/webpack/blob/main/lib/Dependency.js">dependency graph</a> of module objects. Hash-map will also be maintained between the file ID, the absolute path, and the parsed file.</p>
<p>After building the dependency graph, the compiler will topologically sort all dependencies.</p>
<p><strong><em>Topological sorting</em></strong>*: Topological sorting for a Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge u v, vertex u comes before v in the ordering.*</p>
<p>The Webpack <a target="_blank" href="https://github.com/webpack/webpack/blob/main/lib/Template.js">merges</a> all these topologically sorted dependencies with the help of a <a target="_blank" href="https://github.com/webpack/webpack/blob/main/lib/ChunkGraph.js">maintained hash map</a> to make a bundle file. <strong>Minification</strong> or <strong>tree-shaking</strong> can be done on these bundle files now as <strong>post-processing</strong> measures through an event listener, which is also called a plugin. That’s it! Bundler has done his job in these simple steps :)</p>
<p>Let’s dry run the above bundling process for <a target="_blank" href="https://github.com/KhushilMistry/webpack-testing">the following code</a>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// cat.js ES Module</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-string">"cat"</span>;

<span class="hljs-comment">// bar.js CommonJS</span>
<span class="hljs-keyword">const</span> cat = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./cat"</span>);
<span class="hljs-keyword">const</span> bar = <span class="hljs-string">"bar"</span> + cat;
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = bar;

<span class="hljs-comment">// foo.js ES Module</span>
<span class="hljs-keyword">import</span> catString <span class="hljs-keyword">from</span> <span class="hljs-string">'./cat'</span>;
<span class="hljs-keyword">const</span> fooString = catString + <span class="hljs-string">"foo"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> fooString;

<span class="hljs-comment">// index.js - entry point</span>
<span class="hljs-keyword">import</span> fooString <span class="hljs-keyword">from</span> <span class="hljs-string">'./foo'</span>;
<span class="hljs-keyword">import</span> barString <span class="hljs-keyword">from</span> <span class="hljs-string">'./bar'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./tree.jpeg'</span>;
<span class="hljs-built_in">console</span>.log(fooString, barString);
</code></pre>
<p>index.js is an entry for the bundler. The compiler will start the process with this information. It will convert the relative path into the absolute path and make a module object. We don’t need any transpiler here as it’s a simple JavaScript file. Now the parser will start parsing the index file. It contains 3 import statements, so the final object module created for index.js will look like this.</p>
<pre><code class="lang-typescript">{
  <span class="hljs-string">"id"</span>:<span class="hljs-number">0</span>,
  <span class="hljs-string">"absolutePath"</span>:<span class="hljs-string">"$home/index.js"</span>,
  <span class="hljs-string">"bundledFile"</span>: <span class="hljs-string">"bundledFile0.js"</span>,
  <span class="hljs-string">"fileType"</span>:<span class="hljs-string">".js"</span>,
  <span class="hljs-string">"dependency"</span>:[
    { <span class="hljs-string">"id"</span>: <span class="hljs-number">1</span>, <span class="hljs-string">"path"</span>: <span class="hljs-string">"./foo"</span> },
    { <span class="hljs-string">"id"</span>: <span class="hljs-number">2</span>, <span class="hljs-string">"path"</span>: <span class="hljs-string">"./bar"</span> },
    { <span class="hljs-string">"id"</span>: <span class="hljs-number">3</span>, <span class="hljs-string">"path"</span>: <span class="hljs-string">"./tree.jpeg"</span>}
  ]
}
</code></pre>
<p>Webpack will now start compiling the dependencies of <em>index.js</em>. Webpack will recursively compile all the files until there are no dependencies left for any file and form the following dependency graph. Here, <em>tree.jpeg</em> will require a file loader/transpiler as <em>NodeJS</em> can’t understand it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748522784752/2c9fe20d-4ea5-4550-8eb7-ee429d03d498.png" alt class="image--center mx-auto" /></p>
<p>It will sort all the module objects in topological order and merge their converted chunks to form a <a target="_blank" href="https://github.com/KhushilMistry/webpack-testing/blob/master/build/bundle.js">bundle file</a> for the browser to run directly.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748522896482/0fd1430e-bf74-4882-8d23-7610dc259f4a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-core-concepts-of-webpack">The core concepts of Webpack</h2>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*-SXPGmftK_urMG5_.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-core-concepts-of-webpack-1">The Core Concepts of Webpack</h2>
<p>The core concepts in Webpack:</p>
<ul>
<li><p>Entry</p>
</li>
<li><p>Output</p>
</li>
<li><p>Loaders</p>
</li>
<li><p>Plugins</p>
</li>
<li><p>Mode</p>
</li>
<li><p>Development Server</p>
</li>
</ul>
<h3 id="heading-entry">Entry</h3>
<p><code>entry</code> is the entry point of your application. This is the place where Webpack starts its journey. We know that our React applications are like a tree. All the components span out from <code>App.js</code>.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1316/1*N7I3ik50EHDisWCN33qVYw.png" alt="App architecture" /></p>
<p>But where do our <code>App.js</code> live? It lives inside the <code>index.js</code> file, and that’s why webpack enters the application via <code>index.js</code> and creates a dependency graph to determine which files need to be loaded first.</p>
<h3 id="heading-output">Output</h3>
<p>This is another easy concept to understand. After all the work is done, Webpack creates a bundle file. In <code>output</code>, we can specify the name and the location of the output file.</p>
<p>It also has other uses. If you want to generate bundle names for the production system for version management, you can do that here.</p>
<p>Let’s take this a step further and try to understand how our <code>.jsx</code> or <code>.css</code> files are handled.</p>
<h3 id="heading-loader">Loader</h3>
<p>Loaders are a very important concept in Webpack. They are like compilers, Webpack checks for a certain type of file and uses appropriate loaders to handle them.</p>
<p>A typical configuration of the <code>loader</code> can be like the following:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
    entry: { ... <span class="hljs-keyword">as</span> before}
    output: { ... <span class="hljs-keyword">as</span> before },

    <span class="hljs-keyword">module</span>: {
        rules: [
            {
                test: <span class="hljs-regexp">/\.[jt]sx?$/</span>, <span class="hljs-comment">// matches .js, .ts, .jsx and .tsx files</span>
                use: [<span class="hljs-string">'babel-loader'</span>],, <span class="hljs-comment">// uses babel-loader for the specified file types</span>
                include: path.resolve(__dirname, <span class="hljs-string">'src'</span>),
                exclude: <span class="hljs-regexp">/node_modules/</span>,
            }
        ],
    }
}
</code></pre>
<p>Now, look at the <code>module</code> part. It takes an array of rules. Each rule has several parts:</p>
<ul>
<li><p><code>test</code> -&gt; It checks for a certain file type. It uses a regular expression.</p>
</li>
<li><p><code>use</code> -&gt; It specifies the list of loaders used for this particular file type.</p>
</li>
<li><p><code>include</code> -&gt; Which files should be processed?</p>
</li>
<li><p><code>exclude</code> -&gt; Which should not be processed.</p>
</li>
</ul>
<p>Sometimes we need more than one type of loader for a specific file. A good example is loading <code>CSS</code> files. The rule for that is:</p>
<pre><code class="lang-typescript">{
    test: <span class="hljs-regexp">/\.css$/</span>, <span class="hljs-comment">// matches .css files only</span>
    use: [<span class="hljs-string">'style-loader'</span>, <span class="hljs-string">'css-loader'</span>],
},
</code></pre>
<p>Here, both <code>css-loader</code> and <code>style-loader</code> are used to process the file. One important thing to note here is that these loaders are loaded in the reverse order.</p>
<p>That means first the <code>css-loader</code> will work and then <code>style-loader</code> will work on the output produced by <code>css-loader</code>.</p>
<p>Similarly, for our <code>.scss</code> files:</p>
<pre><code class="lang-typescript">{
  test: <span class="hljs-regexp">/\.scss$/</span>,
  use: [<span class="hljs-string">'style-loader'</span>, <span class="hljs-string">'css-loader'</span>, <span class="hljs-string">'sass-loader'</span>]
},
</code></pre>
<h3 id="heading-plugins">Plugins</h3>
<p>Almost 80% of Webpack runs on plugins.</p>
<p>Plugins are another very important aspect of Webpack. Plugins are the main reason why Webpack is so powerful.</p>
<p>Plugins are like libraries. They can tap into any stage of the compilation process and do whatever they wish.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> {CleanWebpackPlugin} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'clean-webpack-plugin'</span>)

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = merge(common ,{
    entry:  {...},
    output: {...},
    <span class="hljs-keyword">module</span>: {...}

    plugins: [ <span class="hljs-keyword">new</span> CleanWebpackPlugin() ]
})
</code></pre>
<p>In the example above, we used a plugin named <code>clean-webpack-plugin</code>. What this plugin does is clean the output folder each time we run our build command.</p>
<p>There are lots of plugins that you can take advantage of. You can refer to <a target="_blank" href="https://webpack.js.org/plugins/">WebPack’s official website</a> if you are interested.</p>
<h3 id="heading-mode">Mode</h3>
<p>This is the simple concept to understand. You would want to use a different setup for your development and production. For this, you can use <code>mode</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = merge(common ,{
    entry:  {...},
    output: {...},
    <span class="hljs-keyword">module</span>: {...},
    plugins:{...},

    mode : <span class="hljs-string">'development'</span> or <span class="hljs-string">'production'</span>
})
</code></pre>
<p>If you set the mode to <code>production</code>, then your output bundle will be minified and optimized.</p>
<h3 id="heading-development-server">Development Server</h3>
<p>This is the final setup for your application. While developing the application, you will not want to compile it every time you change something. That’s why you need a <code>devServer</code> setup for your application.</p>
<pre><code class="lang-typescript">
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = merge(common ,{
    entry:  {...},
    output: {...},
    <span class="hljs-keyword">module</span>: {...},
    plugins:{...},
    mode :  {...},

    devServer: {
        contentBase: path.join(__dirname, <span class="hljs-string">'public/'</span>),
        port: <span class="hljs-number">3000</span>,
        publicPath: <span class="hljs-string">'http://localhost:3000/dist/'</span>,
        hotOnly: <span class="hljs-literal">true</span>,
    },
})
</code></pre>
<p>Now, this setup will serve your application from the <code>dist</code> that you set up earlier as your <code>output</code>.</p>
<h2 id="heading-why-frontend-engineers-need-to-be-webpack-experts">Why Frontend Engineers Need to be WebPack experts</h2>
<p>Modern web applications are not just about core functionalities. We also pay attention to factors like application performance, development productivity, and efficiency to get the maximum out of our effort.</p>
<blockquote>
<p>But, are you aware that you could use WebPack to address some of these challenges?</p>
</blockquote>
<p>However, just knowing how WebPack works won’t be enough to get the maximum from it. So, let’s see what you can achieve by being an expert in Webpack.</p>
<h3 id="heading-improve-development-productivity">Improve Development Productivity</h3>
<p>As developers, we always like to see faster feedback while we carry out modifications to the code. Besides, there are various methods we follow.</p>
<p>If you know WebPack well, you can easily enable its Hot Module Replacement feature to improve the development process.</p>
<p>Hot Module Replacement (HMR) allows us to modify modules while it is in the running state. Since HMR prevents full reload of the application, it will remain in the same state and will only be updated with what has changed.</p>
<p>All you need is to update the <a target="_blank" href="https://github.com/webpack/webpack-dev-server">weppack-dev-server</a> configuration and use its built-in <a target="_blank" href="https://webpack.js.org/plugins/hot-module-replacement-plugin/">HMR plugin</a>.</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  entry: {
    app: <span class="hljs-string">'./src/index.js'</span>,
  },
  ...
  devServer: {
    contentBase: <span class="hljs-string">'./dist'</span>,
    hot: <span class="hljs-literal">true</span>,  <span class="hljs-comment">// &lt;--- Add this line</span>
  },
  plugins: [
    ...
    <span class="hljs-keyword">new</span> HtmlWebpackPlugin({
      title: <span class="hljs-string">'Hot Module Replacement'</span>,
    }),
  ],
  output: {
      ...
  },
};
</code></pre>
<blockquote>
<p>Pro tip: HMR becomes very handly in situations where you develop applications for multiple devices form factors. E.g., you can access the development server URL on both desktop and mobile and instantly see how it looks in both.</p>
</blockquote>
<h3 id="heading-get-better-at-tree-sharking">Get Better at Tree-Sharking</h3>
<p>If your project has a significant amount of dead code or a large number of <a target="_blank" href="https://blog.bitsrc.io/building-a-react-component-library-d92a2da8eab9">shared libraries</a>, it’s common to experience a long application loading time. It’s common to see tree-shaking in such situations to avoid dead or unwanted code from bundling.</p>
<pre><code class="lang-typescript">....
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  entry: {
    app: <span class="hljs-string">'./src/index.js'</span>,
  },
  output: {
      ...
  },
  <span class="hljs-comment">//add below line </span>
  mode: <span class="hljs-string">'development'</span>,
  optimization: {
    usedExports: <span class="hljs-literal">true</span>,
  },
};
</code></pre>
<p><strong>But, how can we guarantee that WebPack makes a correct decision about unused code in the project?</strong></p>
<p>For example, it’s common to have global-level stylesheets imported into the project, and usually, those files aren’t used anywhere. But removing such files can affect the whole project.</p>
<p>Webpack uses a special configuration in the <code>package.json file</code> named <code>sideEffects</code>. By default, all the files in your project are considered files with side effects, and tree-shaking won’t be performed.</p>
<p><strong>However, we can manually change this behavior by changing</strong> <code>sideEffects</code> <strong>value to false, true, or providing an array with file names.</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// All files have side effects </span>
<span class="hljs-string">"sideEffects"</span>: <span class="hljs-literal">true</span>
<span class="hljs-comment">// No files have side effects</span>
<span class="hljs-string">"sideEffects"</span>: <span class="hljs-literal">false</span>
<span class="hljs-comment">//Only these files have side effects,</span>
 <span class="hljs-string">"sideEffects"</span>: [
  <span class="hljs-string">"./src/file1.js"</span>,
  <span class="hljs-string">"./src/file2.js"</span>
 ]
}
</code></pre>
<p>If you enable tree-shaking in Webpack configuration, ensure to include files that don’t have side effects in <code>package.json</code> file settings.</p>
<h3 id="heading-using-code-splitting-to-optimize-app-loading-time">Using Code Splitting to Optimize App Loading Time</h3>
<p>If you monitor the number of unused bytes in a single bundle using Chrome DevTools, you will be amazed to see how often it happens.</p>
<p>Webpack provides the perfect situation by allowing you to split your code into different bundles and load them on-demand or in parallel.</p>
<blockquote>
<p>Webpack provides 3 approaches for code splitting, and you will need to decide which mechanism is the most suited one for your project. For that, you should have a good understanding of Webpack.</p>
</blockquote>
<p>The <strong>entry point</strong> approach is considered the most straightforward and most used code-splitting approach with Webpack. You just need to update all the separate modules in the Webpack config file manually.</p>
<pre><code class="lang-typescript">....
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  mode: <span class="hljs-string">'development'</span>,
  entry: {
    index: <span class="hljs-string">'./src/index.js'</span>,
    second: <span class="hljs-string">'./src/second-module.js'</span>,
  },
  output: {
   filename: <span class="hljs-string">'[name].bundle.js'</span>,
   path: path.resolve(__dirname, <span class="hljs-string">'dist'</span>),
   },
};
</code></pre>
<p>However, this approach is not very flexible, and there is a risk of having duplicate modules between chunks. If you don’t see any improvements with this approach, you can go deeper with the <strong>Prevent Duplication</strong> approach**.**</p>
<p><strong>Prevent Duplication</strong> approach allows specifying the shared modules between chunks using <code>dependOn</code> the option. You can easily convert the entry point approach to prevent duplication with a few modifications.</p>
<pre><code class="lang-typescript">....
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  mode: <span class="hljs-string">'development'</span>,
  entry: {
    index: {
      <span class="hljs-keyword">import</span>: <span class="hljs-string">'./src/index.js'</span>,
      dependOn: <span class="hljs-string">'shared'</span>,
    }, 
    second: {
      <span class="hljs-keyword">import</span>: <span class="hljs-string">'./src/second.js'</span>,
      dependOn: <span class="hljs-string">'shared'</span>,
    }, 
    shared: <span class="hljs-string">'shared-module'</span>,
  },
 ...
};
</code></pre>
<p>But the above configuration alone will not give you the desired output. You also need to enable <code>runtimeChunk</code> in the <code>optimization</code> section to prevent Webpack from copying module code between entry points.</p>
<pre><code class="lang-typescript">optimization: {
  splitChunks: {
    chunks: <span class="hljs-string">'all'</span>,
  },
},
</code></pre>
<p>If you are not satisfied with the Prevent Duplication approach, you can shift to the <a target="_blank" href="https://webpack.js.org/guides/code-splitting/#dynamic-imports">Dynamic Imports</a> approach.</p>
<p>I think you already understand the power of Webpack code splitting and the amount of knowledge you need to configure that. So, I won’t be going into details of the <a target="_blank" href="https://webpack.js.org/guides/code-splitting/#dynamic-imports">Dynamic Imports</a> approach here, and you will be able to understand it easily if you understood the previous two.</p>
<h3 id="heading-supports-micro-frontends-with-module-federation">Supports Micro Frontends with Module Federation</h3>
<blockquote>
<p>Module federation is an exciting JavaScript architecture that allows importing code from another application dynamically at runtime.</p>
</blockquote>
<p>Webpack facilitates the support you need to integrate the module federation architecture to your project through a plugin called Module <strong>Federation Plugin.</strong></p>
<p>All you need to do is follow the 4 simple steps:</p>
<ol>
<li><p>Import the plugin to both applications.</p>
</li>
<li><p>Make necessary modifications in the Webpack configuration for the first application and expose the components that need to be shared.</p>
</li>
<li><p>Import the shared component in the Webpack configurations of the second application.</p>
</li>
</ol>
<p>However, this might not be that simple when you start the implementation. You should be very careful about Webpack configurations and only necessary changes.</p>
<p>For example, in the first application, you won’t need to change anything other than the plugins section.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> { ModuleFederationPlugin } = <span class="hljs-built_in">require</span>(“webpack”).container;
...
plugins: [
  <span class="hljs-keyword">new</span> ModuleFederationPlugin({
    name: <span class="hljs-string">"application1"</span>,
    library: { <span class="hljs-keyword">type</span>: <span class="hljs-string">"var"</span>, name: <span class="hljs-string">"app1"</span> },
    filename: <span class="hljs-string">"remoteEntry.js"</span>,
    exposes: {
      <span class="hljs-comment">// expose each component</span>
      <span class="hljs-string">"./Component1"</span>: <span class="hljs-string">"./src/components/Component1"</span>,
    },
      shared: [<span class="hljs-string">"react"</span>, <span class="hljs-string">"react-dom"</span>],
    }),
    ...
  ],
...
</code></pre>
<p>Besides, if you have a good understanding of these concepts, you can refer to the relevant <a target="_blank" href="https://webpack.js.org/concepts/module-federation/">documentation</a> and easily carry out the required configurations.</p>
<p>With this approach, you will be able to move away from the traditional way of sharing reusable components between micro frontends, and I think that would be a huge win for your development team.</p>
<h2 id="heading-how-to-set-up-your-react-app-from-scratch-using-webpack">How to set up your React app from scratch using Webpack</h2>
<p>So, you have been using Create React App, aka CRA, for a while now. It’s great, and you can get straight to coding. But when do you need to eject from create-react-app and start configuring your own React application? There will be a time when we have to let go of the safety check and start venturing out of our own.</p>
<p>Let’s check out these articles:</p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/an-intro-to-webpack-what-it-is-and-how-to-use-it-8304ecdc3c60/">https://www.freecodecamp.org/news/an-intro-to-webpack-what-it-is-and-how-to-use-it-8304ecdc3c60/</a></p>
<p><a target="_blank" href="https://raphael-leger.medium.com/react-webpack-chunkloaderror-loading-chunk-x-failed-ac385bd110e0">https://raphael-leger.medium.com/react-webpack-chunkloaderror-loading-chunk-x-failed-ac385bd110e0</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/learn-webpack-in-under-10-minutes-efe2b2b10b61">https://medium.com/better-programming/learn-webpack-in-under-10-minutes-efe2b2b10b61</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/webpack-in-2021-typescript-jest-sass-eslint-7b4640842e27">https://javascript.plainenglish.io/webpack-in-2021-typescript-jest-sass-eslint-7b4640842e27</a></p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/how-to-set-up-deploy-your-react-app-from-scratch-using-webpack-and-babel-a669891033d4/">https://www.freecodecamp.org/news/how-to-set-up-deploy-your-react-app-from-scratch-using-webpack-and-babel-a669891033d4/</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/a-complete-guide-to-use-typescript-in-web-development-with-without-react-3ab58ab4f03c">https://javascript.plainenglish.io/a-complete-guide-to-use-typescript-in-web-development-with-without-react-3ab58ab4f03c</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/micro-frontends-using-webpack-5-module-federation-3b97ffb22a0d">https://medium.com/better-programming/micro-frontends-using-webpack-5-module-federation-3b97ffb22a0d</a></p>
<p><a target="_blank" href="https://medium.com/swlh/webpack-5-module-federation-a-game-changer-to-javascript-architecture-bcdd30e02669">https://medium.com/swlh/webpack-5-module-federation-a-game-changer-to-javascript-architecture-bcdd30e02669</a></p>
<h1 id="heading-bundler-best-practices">Bundler Best Practices</h1>
<h2 id="heading-webpack-and-yarn-magic-against-duplicates-in-bundles">Webpack and yarn magic against duplicates in bundles</h2>
<h3 id="heading-setting-up-the-scene">Setting up the scene</h3>
<p>I will assume that you have some understanding of what tools like yarn, npm, and webpack are used in modern frontend projects and want to dig deeper into the magic behind the scenes.</p>
<p>Some terminology used in this article:</p>
<p><strong>Direct dependencies</strong>: packages on which your project relies explicitly. Typically installed via yarn add package-name. The full list of those can be found in the dependencies field in package.json at the root of the project.</p>
<p><strong>Transitive dependencies</strong>: packages on which your project relies implicitly. Those are the dependencies on which your direct dependencies rely. Typically, you won’t see them in the <code>package.json</code> file, but they can be seen, for example, in <code>yarn.lock</code> file</p>
<p><strong>Duplicated Dependencies:</strong> transitive dependencies with mismatched versions. If one of the project dependencies has a button package version 4.0.0 as a transitive dependency and another has the same button version 3.0.0, both of those versions will be installed, and the button dependency will be duplicated.</p>
<p><strong>De-duplication</strong>: the process of elimination of duplicated dependencies according to their <a target="_blank" href="https://semver.org/">SemVer</a> versions (x.x.x - major, minor, patch). Typically, a range of versions within the same major version will contain no breaking changes, and only the latest version within this range can be installed. For example, a button version 4.0.0 and 4.5.6 can be “de-duplicated, “ and only version 4.5.6 will be installed.</p>
<p><code>yarn.lock</code> <strong>file</strong>: an auto-generated file that contains the exact and full list of all direct and transitive dependencies and their exact versions in yarn-based projects.</p>
<h3 id="heading-the-problem-of-duplicated-dependencies">The problem of duplicated dependencies</h3>
<p>“Duplicated“ dependencies in any of the middle — or large-scale projects that rely on npm packages are inevitable. When a project has dozens of “direct“ dependencies, and every one of those has its own dependencies, the final number of all packages (direct and transitive) installed in a project can be close to hundreds. In this situation, it’s more likely than not that some of the dependencies will be duplicated.</p>
<p>Considering that those are bundled together and served to the customers, in order to reduce the final JavaScript size it’s important to reduce the number of duplicates to a minimum. This is where the deduplication process comes into play.</p>
<h3 id="heading-deduplication-in-yarn">Deduplication in yarn</h3>
<p>Consider, for example, a project that among its direct dependencies has <em>modal-dialog@3.0.0</em> and <em>button@2.5.0</em>, and modal-dialog brings <em>button@2.4.1</em> as a transitive dependency. If left unduplicated, both buttons will exist in the project</p>
<p><img src="https://www.developerway.com/assets/webpack-and-yarn/image1.png" alt class="image--center mx-auto" /></p>
<p>and in <code>yarn.lock</code> , we will see something like this:</p>
<pre><code class="lang-typescript">modal-dialog@^<span class="hljs-number">3.0</span><span class="hljs-number">.0</span>:
  version <span class="hljs-string">"3.0.0"</span>
  resolved <span class="hljs-string">"exact-link-to-where-download-modal-dialog-3.0.0-from"</span>
  dependencies:
    button@^<span class="hljs-number">2.4</span><span class="hljs-number">.1</span>

button@^<span class="hljs-number">2.5</span><span class="hljs-number">.0</span>:
  version <span class="hljs-string">"2.5.0"</span>
  resolved <span class="hljs-string">"exact-link-to-where-download-2.5.0-version-from"</span>

button@^<span class="hljs-number">2.4</span><span class="hljs-number">.1</span>:
  version <span class="hljs-string">"2.4.1"</span>
  resolved <span class="hljs-string">"exact-link-to-where-download-2.4.1-version-from"</span>
</code></pre>
<p>Now, we know that according to semver, button@2.4.1 and button@2.5.0 are compatible, and therefore we can tell yarn to grab the same button@2.5.0 version for both of them — “deduplicate” them. From the project perspective, it will look like this:</p>
<p><img src="https://www.developerway.com/assets/webpack-and-yarn/image3.png" alt /></p>
<p>and in yarn.lock file, we’ll see this:</p>
<pre><code class="lang-typescript">modal-dialog@^<span class="hljs-number">3.0</span><span class="hljs-number">.0</span>:
  version <span class="hljs-string">"3.0.0"</span>
  resolved <span class="hljs-string">"exact-link-to-where-download-modal-dialog-3.0.0-from"</span>
  dependencies:
    button@^<span class="hljs-number">2.4</span><span class="hljs-number">.1</span>

button@^<span class="hljs-number">2.4</span><span class="hljs-number">.1</span>, button@^<span class="hljs-number">2.5</span><span class="hljs-number">.0</span>:
  version <span class="hljs-string">"2.5.0"</span>
  resolved <span class="hljs-string">"exact-link-to-where-download-2.5.0-version-from"</span>
</code></pre>
<h3 id="heading-deduplication-in-yarn-not-compatible-version">Deduplication in yarn - not compatible version</h3>
<p>The above duplication technique is the only thing that we usually have in the fight against duplicates, and usually, it works quite well. But what will happen if a project has non-semver-dedupable transitive dependencies? If, for example, our project has <code>modal-dialog@3.0.0</code>, <code>button@2.5.0</code>, and <code>editor@5000.0.0</code> as direct dependencies, and those bring <code>button@1.3.0</code> and <code>button@1.0.0</code> as transitive dependencies?</p>
<p>Using the same technique, we can de-duplicate buttons from <code>1.x.x</code> version, and from the project perspective, it will look like this:</p>
<p><img src="https://www.developerway.com/assets/webpack-and-yarn/image5.png" alt class="image--center mx-auto" /></p>
<p>Two versions of the button are unavoidable, and in this case, usually, there is nothing we can do other than upgrade the version of model-dialog and editor to the versions when they both have button from 2.x.x range and it can be de-duplicated properly. Typically, in this case, we stop, say that our project has “2 versions of buttons,” and move on with our lives.</p>
<p>But what if we dig a little bit further and check out how exactly 2 buttons are installed on the disk and bundled together?</p>
<h3 id="heading-duplicated-dependencies-installed">Duplicated dependencies installed</h3>
<p>When we install our dependencies via classic yarn or npm (pnpm or yarn 2.0 changes the situation and are not considered here), npm hoists everything that is possible up to the root node_modules. If, for example, in our project above, both the editor and the modal dialog have the dependency on the same “deduped“ version of the tooltip, but our project does not, npm will install it at the root of the project.</p>
<p><img src="https://www.developerway.com/assets/webpack-and-yarn/image7.png" alt class="image--center mx-auto" /></p>
<p>And inside the node_modules folder, we’ll see this structure:</p>
<pre><code class="lang-typescript">/node_modules
  /editor
  /modal-dialog
  /tooltip
</code></pre>
<p>And because of that, we can be sure that we only have one version of the tooltip in the project, or even if two completely different dependencies depend on slightly different versions of it.</p>
<p>Unless…</p>
<p>Unless those versions are not semver compatible and can not be deduplicated that easily. Basically, the situation in the project with buttons from above will look like this:</p>
<p><img src="https://www.developerway.com/assets/webpack-and-yarn/image9.png" alt class="image--center mx-auto" /></p>
<p>Even if dependencies are “deduped” on yarn.lock level, and we “officially” have only 2 versions of buttons in <code>yarn.lock,</code> every single package, with <code>button@1.3.0</code> as the dependency that will install its own copy of it.</p>
<h3 id="heading-deduplicated-dependencies-and-webpack">Deduplicated Dependencies and Webpack</h3>
<p>So, if a project is bundled with Webpack, how exactly does it handle the situation from above? It doesn’t actually (there was a webpack dedup plugin in the long past, but it was removed after Webpack 2.0)</p>
<p>Webpack, behind the scenes, just builds the graph of all your files and their dependencies based on what’s installed and required in your node_modules via the <a target="_blank" href="https://nodejs.org/api/modules.html">normal code resolution algorithm</a>. TL;DR: Every time a file in the editor does “import Button from ‘button’;”, the node will try to find this button in the closest node_modules starting from the parent folder of the file where the request appeared. The same story with the modal-dialog. And then, from a Webpack perspective, the very final ask for the button will be:</p>
<ul>
<li><p><em>project/node_modules/editor/node_modules/button/index.js</em> — when it’s requested from within editor</p>
</li>
<li><p><em>project/node_modules/modal-dialog/node_modules/button/index.js</em> — when it’s requested from within modal-dialog</p>
</li>
</ul>
<p>Webpack is not going to check whether they are exactly the same; it will treat them as unique files and bundle both of them in the same bundle. Our “duplicated” button just got double-duplicated.</p>
<h3 id="heading-deduplication-in-webpack-first-attempt">Deduplication in Webpack - first attempt</h3>
<p>Since those buttons are exactly the same, the very first question that comes to mind is: is it possible to take advantage of that and “trick“ Webpack into recognizing it? And indeed, it is possible, and it is ridiculously simple.</p>
<p>Webpack is incredibly flexible; it provides rich plugin interfaces with access to almost everything you can imagine (and to some things that you can not), and its core, most of its features are built with plugins as well. It <a target="_blank" href="https://webpack.js.org/plugins/">exports a lot of them</a> for others to use.</p>
<p>One of those plugins is <a target="_blank" href="https://webpack.js.org/plugins/normal-module-replacement-plugin/">NormalModuleReplacementPlugin</a> — it gives the ability to replace one file with another file during a build time with a regular expression. Which is exactly what we need; the rest is just a master of coding.</p>
<p>First, detected all “duplicated“ dependencies by grabbing a list of all packages <code>node_modules</code> and filtering those that have node_modules in their install path more than once (basically all the “nested” packages from the yarn install chapter above), and grouping them by their version from package.json.</p>
<p><img src="https://www.developerway.com/assets/webpack-and-yarn/image10.png" alt /></p>
<p>Second, replace all encounters of the “same” package with the very first one from the list</p>
<p><img src="https://www.developerway.com/assets/webpack-and-yarn/image11.png" alt /></p>
<p>And 💥, there is no “third”, the solution works, it’s safe, and reduces bundle sizes in Jira by ~10%.</p>
<p><img src="https://www.developerway.com/assets/webpack-and-yarn/image12.png" alt /></p>
<p>The full implementation was literally just 100 lines. Be mindful with celebrating and copying the approach, though, this is not the end of the article 😉</p>
<p>Check out <a target="_blank" href="https://www.developerway.com/posts/webpack-and-yarn-magic-against-duplicates-in-bundles">this article</a> for more details.</p>
<h2 id="heading-learning-by-fixing-nodejs-modules-and-packages">Learning by fixing: Node.js, Modules, and Packages</h2>
<p>The project I was working on has a pretty standard frontend code setup: React, Next.js, CSS in JS, UI components from an external library to build the interface. One day I added a new component, and although everything works locally, my CI, while attempting to build the website, greeted me with this:</p>
<p><img src="https://www.developerway.com/assets/learning-by-fixing/image1.png" alt /></p>
<p>After a bit of “errr, wat?”, scratching my head furiously, meddling with UI configuration and doing usual clean-the-cache, nuke-node-modules, cargo-culting activities, I managed to reproduce the problem locally. Turned out that:</p>
<ul>
<li><p>It only happens with the Logengy component, which uses Compiled - a new CSS-in-JS library.</p>
</li>
<li><p>It was working locally because the version of Node in the CI was newer than my local machine.</p>
</li>
</ul>
<p>So clearly, the problem was either with Lozenge or with the compiled library itself, and clearly, there was something in their code that prevented it from working with the latest Node. So the solution to the problem seemed simple: downgrade the version of Node in the CI to unblock my build and raise an issue with the <a target="_blank" href="https://github.com/atlassian-labs/compiled/issues/501">library</a> in the hope that maintainers, who know their source code, can figure it out.</p>
<p>Only…</p>
<p>What can <em>possibly</em> a Lozenge component, that just renders a few divs, or a css-in-js library, that converts js-written styles into <code>style</code> tags can have, that depends on a version of Node? Especially on an <em>old</em> version of Node? It’s usually the other way around…</p>
<p>It’s a proper mystery! Time to put my Sherlock hat on and solve it.</p>
<p>Check out <a target="_blank" href="https://www.developerway.com/posts/learning-by-fixing-node-js-modules-and-packages">this article</a> to explore the reason.</p>
<h2 id="heading-three-simple-tricks-to-speed-up-yarn-install">Three simple tricks to speed up yarn install</h2>
<p>Dev productivity and quality of life improvements are a passion of mine. And speeding up working with code is not only fun, but also essential for building products fast. Happier and faster developers equal happier customers, who get their features and bug fixes sooner!</p>
<p>When dealing with an npm-based ecosystem and its myriad of packages, install dependencies time, especially in large projects, can be unreasonably long. Below are three simple tricks that can help you shave off a minute or two, or sometimes even reduce your <code>yarn install</code> time by half 😋</p>
<p><img src="https://www.developerway.com/assets/speed-up-yarn-install/compiling.png" alt class="image--center mx-auto" /></p>
<p>Not anymore!</p>
<h2 id="heading-bloated-yarnlock-problem"><strong>Bloated yarn.lock problem</strong></h2>
<p>If your project runs on yarn, then more likely than not, some of your dependencies will be duplicated, even if they satisfy semver conditions. Although <a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/">yarn</a> <a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/">promises tha</a>t deduplication isn’t necessary, this is not exactly the truth.</p>
<p>Imagine the situation: you’re adding <code>@awesome/tools</code> library to your dependencies, which also depends on <code>utils@^1.0.0</code>library, which is its latest version. After installing <code>@awesome/tools</code> you’ll s<a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/">ee in your <code>ya</code></a><code>rn.lock</code> file:</p>
<p><img src="https://www.developerway.com/assets/speed-up-yarn-install/image1.png" alt /></p>
<p>After a few months, you want to add another library that depends on those utils, let’s say <code>@simple/button</code>.The Utils library released a few bug fixes and features in the meantime, and its latest version is now <code>1.5.1</code>, and <code>@simple/button</code>depends on it. If you just <a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/">run <code>yarn add</code></a> <code>@</code><a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/"><code>simple/button</code></a>, then in the <a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/"><code>yarn.lock</code> you</a> will see this picture:</p>
<p><img src="https://www.developerway.com/assets/speed-up-yarn-install/image2.png" alt /></p>
<p>Even though <code>1.5.1</code> and <code>1.0.0</code> versions are semver-compatible, yarn will not merge them into one as you’d expect, and you’ll end up with 2 versions of the same <code>utils</code> in the repo.</p>
<p>It gets worse tha<a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/">n that. If yo</a>u have a few different libraries that depend on version <code>1.0.0</code> and a few that depend on <code>1.5.1</code>, yarn will hoist one of those versions to the root of <code>node_modules</code> folder, but another one would have no place to go <a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/">(only one ver</a>sion can sit at the root), and they will be installed as <strong><em>copies</em></strong> in <code>node_modules</code> folders of the libraries that use them. You’ll end up with this folder structure:</p>
<p><img src="https://www.developerway.com/assets/speed-up-yarn-install/image3.png" alt /></p>
<p>And although it <em>seems</em> like you only have 2 versions of <code>utils</code> library, in reality, it can be 5–6-infinite-number of its copies living in your project, all of whi<a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/">ch need to be</a> copied into their place, and all of which will steal your <code>yarn install</code> time.</p>
<p>Check out <a target="_blank" href="https://www.developerway.com/posts/three-simple-tricks-to-speed-up-yarn-install">this article</a> to explore the solution🔥</p>
<h2 id="heading-how-did-we-cut-bundle-size-by-70-overnight">How did we cut bundle size by 70% overnight?</h2>
<p>An analysis of modern JavaScript projec<a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/">ts reveals a</a> concerning trend: many production applications include hundreds of transitive dependencies. According to Sonatype’s 2023 research, the average JavaScript contains 42 direct dependencies and 683 transitive dependencies, with 65% of projects containing known vulnerable dependencies.</p>
<p>The real cost goes so far beyond the megabytes:</p>
<ul>
<li><p><strong>Security Vulnerabilities</strong>: Each dependency is a potential attack vect<a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/">or.</a></p>
</li>
<li><p><a target="_blank" href="https://classic.yarnpkg.com/en/docs/cli/dedupe/"><strong>Maint</strong></a><strong>enance overhead</strong>: Keeping dependencies updated consumes developer time.</p>
</li>
<li><p><strong>Version conflicts</strong>: Incompatible sub-dependencies create debugging nightmares.</p>
</li>
<li><p><strong>Bundle bloated</strong>: Libraries often bring more code than you actually use.</p>
</li>
</ul>
<p>Most concerning is the exponential nature of transitive dependencies. Adding a “single“ package can sometimes pull in dozens of sub-dependencies you never intended to include.</p>
<p>A client of ours recently added a simple date formatting library that seemed lightweight (12KB) — but it silently pulls in 267KB of additional dependencies. That’s a 22X multiplier!</p>
<p>That matters because every 100kB of JavaScript takes approximately 100ms to parse and compile on an average mobile device.</p>
<p>For users on slower devices or connections, this directly translates to frustration and abandonment.</p>
<h3 id="heading-our-dependency-audit-process">Our dependency audit process</h3>
<ol>
<li><strong>Analyzing the current state</strong></li>
</ol>
<p>Before making any changes, we needed visibility into our dependency mess. These tools proved invaluable:</p>
<p><strong>webpack-bundle-analyzer</strong></p>
<p>Gives you a visual treemap of your bundle components.</p>
<pre><code class="lang-typescript"># Installation
npm install --save-dev webpack-bundle-analyzer
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// # In your webpack.config.js</span>
<span class="hljs-keyword">const</span> { BundleAnalyzerPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack-bundle-analyzer'</span>);
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  plugins: [
    <span class="hljs-keyword">new</span> BundleAnalyzerPlugin()
  ]
}
<span class="hljs-comment">// # Run your build to see the analysis</span>
npm run build
</code></pre>
<p><strong>npm is</strong></p>
<p>Shows your dependency tree directly in the terminal:</p>
<pre><code class="lang-typescript"># Show top-level dependencies
npm ls --depth=<span class="hljs-number">0</span>

# Show all dependencies including their dependencies
npm ls

# Find specific packages
npm ls react

# Show only production dependencies
npm ls --prod
</code></pre>
<p><strong>dep check</strong></p>
<p>Identifies unused dependencies in your projects</p>
<pre><code class="lang-typescript"># Installation
npm install -g depcheck

# Run <span class="hljs-keyword">in</span> your project root
depcheck

# With custom options
depcheck --ignores=<span class="hljs-string">"eslint,babel-*"</span>
</code></pre>
<p><strong>import-cost</strong></p>
<pre><code class="lang-typescript"># Installation steps:
<span class="hljs-number">1.</span> Open VS Code
<span class="hljs-number">2.</span> Press Ctrl+P (Cmd+P on Mac)
<span class="hljs-number">3.</span> Type: ext install wix.vscode-<span class="hljs-keyword">import</span>-cost
<span class="hljs-number">4.</span> Press Enter

# The extension will show size information directly <span class="hljs-keyword">in</span> your editor
# whenever you <span class="hljs-keyword">import</span> packages
</code></pre>
<p>Running webpack-bundle-analyzer was eye-opening. We immediately spotted several massive libraries dominating your bundle:</p>
<ul>
<li><p>A full-featured charting library (1.2MB), when we only used two simple chart types</p>
</li>
<li><p>Three different date manipulation libraries (Moment.js, date-fns, and Day.js)</p>
</li>
<li><p>Lodash is imported in its entirety rather than individual functions.</p>
</li>
<li><p>A massive UI component library where we used just four components.</p>
</li>
</ul>
<ol start="2">
<li><strong>Setting Measurable Goals</strong></li>
</ol>
<p>We established clear metrics to track our progress:</p>
<ul>
<li><p>Primary: Total bundle size (initial and chunked)</p>
</li>
<li><p>Secondary: Time to interact on mid-tier mobile devices.</p>
</li>
<li><p>Supporting: JavaScript parse/compile time</p>
</li>
<li><p>Business: Conversion rates and bounce rates</p>
</li>
</ul>
<p>We set an ambitious goal of reducing bundle size by 50% within one sprint, with a stretch goal of 60%. We ultimately achieved 70%.</p>
<h3 id="heading-6-techniques-that-delivered-results-our-step-by-step-process">6 Techniques that delivered results: Our Step-by-Step Process</h3>
<ol>
<li><strong>Ruless Package Evaluation</strong></li>
</ol>
<p>We applied a simple but effective framework to every dependency:</p>
<ul>
<li><p>Do we absolutely need this functionality?</p>
</li>
<li><p>Can we implement it ourselves in &lt; 100 lines of code?</p>
</li>
<li><p>Is there a more lightweight alternative?</p>
</li>
<li><p>If we must use it, can we only use the needed parts?</p>
</li>
</ul>
<p>This led to some major wins:</p>
<p><strong>Example 1: Replacing Moment.js (329KB) with date-fns (85KB)</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Before: Moment.js (329KB)</span>
<span class="hljs-keyword">import</span> moment <span class="hljs-keyword">from</span> <span class="hljs-string">'moment'</span>;
<span class="hljs-keyword">const</span> formattedDate = moment(date).format(<span class="hljs-string">'YYYY-MM-DD'</span>);
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// After: date-fns (only importing what we need)</span>
<span class="hljs-keyword">import</span> { parseISO, format } <span class="hljs-keyword">from</span> <span class="hljs-string">'date-fns'</span>;
<span class="hljs-keyword">const</span> formattedDate = format(parseISO(dateString), <span class="hljs-string">'yyyy-MM-dd'</span>);
</code></pre>
<p><strong>Example 2: Replacing a full chart library with a targeted solution</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Before: Importing massive chart library (1.2MB)</span>
<span class="hljs-keyword">import</span> { LineChart } <span class="hljs-keyword">from</span> <span class="hljs-string">'massive-chart-lib'</span>;

<span class="hljs-comment">// After: Using a lightweight alternative (87KB)</span>
<span class="hljs-keyword">import</span> { Line } <span class="hljs-keyword">from</span> <span class="hljs-string">'lightweight-charts'</span>;
</code></pre>
<p>In total, we eliminated 18 dependencies and replaced 7 others with lighter alternatives.</p>
<ol start="2">
<li><strong>Implementing Proper Tree-Shaking</strong></li>
</ol>
<p>Tree-shaking (eliminating unused code) sounds simple, but many projects don’t fully benefit from it due to configuration issues.</p>
<p>Common pitfalls we fixed:</p>
<ul>
<li><p>Using CommonJS modules that can’t be properly tree-shaken.</p>
</li>
<li><p>Side effects preventing dead code elimination</p>
</li>
<li><p>Incorrect Webpack/bundler configuration</p>
</li>
</ul>
<p><strong>Our webpack optimization:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// webpack.config.js improvements</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  mode: <span class="hljs-string">'production'</span>,
  optimization: {
    usedExports: <span class="hljs-literal">true</span>,
    sideEffects: <span class="hljs-literal">true</span>,
    minimize: <span class="hljs-literal">true</span>,
    concatenateModules: <span class="hljs-literal">true</span>,
  },
}
</code></pre>
<p><strong>Ensuring proper imports:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Before: No tree-shaking (entire library included)</span>
<span class="hljs-keyword">import</span> _ <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash'</span>;

<span class="hljs-comment">// After: Tree-shakeable imports</span>

<span class="hljs-comment">// Option 1: Individual imports</span>
<span class="hljs-keyword">import</span> map <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash/map'</span>;
<span class="hljs-keyword">import</span> filter <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash/filter'</span>;


<span class="hljs-comment">// Option 2: Using lodash-es for ESM modules</span>
<span class="hljs-keyword">import</span> { map, filter } <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash-es'</span>;
</code></pre>
<p>This alone shaved off 347KB from our bundle.</p>
<ol start="3">
<li><strong>Dynamic Imports &amp; Code Splitting</strong></li>
</ol>
<p>Rather than loading our entire application upfront, we implemented aggressive code splitting:</p>
<p><strong>Route-based splitting:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Before: All routes imported eagerly</span>
<span class="hljs-keyword">import</span> UserProfile <span class="hljs-keyword">from</span> <span class="hljs-string">'./UserProfile'</span>;
<span class="hljs-keyword">import</span> Dashboard <span class="hljs-keyword">from</span> <span class="hljs-string">'./Dashboard'</span>;
<span class="hljs-keyword">import</span> Settings <span class="hljs-keyword">from</span> <span class="hljs-string">'./Settings'</span>;


<span class="hljs-comment">// After: Routes loaded dynamically</span>
<span class="hljs-keyword">const</span> UserProfile = React.lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./UserProfile'</span>));
<span class="hljs-keyword">const</span> Dashboard = React.lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./Dashboard'</span>));
<span class="hljs-keyword">const</span> Settings = React.lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./Settings'</span>));
</code></pre>
<p><strong>Feature-based splitting:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Before: Advanced features loaded upfront</span>
<span class="hljs-keyword">import</span> { DataExport } <span class="hljs-keyword">from</span> <span class="hljs-string">'./features/export'</span>;

<span class="hljs-comment">// After: Load on demand</span>
<span class="hljs-keyword">const</span> handleExport = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> { DataExport } = <span class="hljs-keyword">await</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./features/export'</span>);
  DataExport.run(currentData);
};
</code></pre>
<p>We used <code>React.Suspense</code> to handle loading states gracefully:</p>
<pre><code class="lang-typescript">&lt;Suspense fallback={&lt;Spinner /&gt;}&gt;
  &lt;Route path=<span class="hljs-string">"/profile"</span> component={UserProfile} /&gt;
&lt;/Suspense&gt;
</code></pre>
<p>This approach reduced our initial bundle size by 35% by deferring non-critical features.</p>
<ol start="4">
<li><strong>Micro-frontends for Targeted Loading</strong></li>
</ol>
<p>For our most complex product area — the analytics dashboard — we implemented module federation using Webpack 5’s features to load different sections independently. While this approach took us around three weeks to fully implement (longer than our initial one-week estimate), the performance benefits justified the investment.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// webpack.config.js (simplified)</span>
<span class="hljs-keyword">const</span> { ModuleFederationPlugin } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack'</span>).container;

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  plugins: [
    <span class="hljs-keyword">new</span> ModuleFederationPlugin({
      name: <span class="hljs-string">'dashboard'</span>,
      filename: <span class="hljs-string">'remoteEntry.js'</span>,
      exposes: {
        <span class="hljs-string">'./ReportingModule'</span>: <span class="hljs-string">'./src/components/Reporting'</span>,
        <span class="hljs-string">'./VisualizationModule'</span>: <span class="hljs-string">'./src/components/Visualization'</span>,
      },
      shared: {
        react: { singleton: <span class="hljs-literal">true</span> },
        <span class="hljs-string">'react-dom'</span>: { singleton: <span class="hljs-literal">true</span> },
        <span class="hljs-comment">// other shared dependencies</span>
      },
    }),
  ],
};
</code></pre>
<p>This approach allowed us to:</p>
<ul>
<li><p>Load only the dashboard components that the user actually views</p>
</li>
<li><p>Share common dependencies between micro-frontends</p>
</li>
<li><p>Update individual modules independently</p>
</li>
</ul>
<p><strong>When Not to Use Micro-frontends</strong></p>
<p>While powerful, this approach isn’t for everyone:</p>
<ul>
<li><p><strong>Small teams with limited DevOps resources</strong> may find the operational complexity overwhelming</p>
</li>
<li><p><strong>Applications with heavy cross-module communication</strong> might face performance penalties</p>
</li>
<li><p><strong>Projects requiring SSR/SSG optimization</strong> may need different architectural approaches</p>
</li>
</ul>
<blockquote>
<p><em>⚠️ Not for everyone — Micro-frontends introduce DevOps and architectural complexity. Avoid them for small apps or SSR-focused builds.</em></p>
</blockquote>
<p>For our use case — a large dashboard with distinct functional areas — the benefits far outweighed the complexities.</p>
<ol start="5">
<li><strong>Building Dependencies Approval Process</strong></li>
</ol>
<p>To prevent future bloat, we implemented a dependency approval workflow:</p>
<ol>
<li><p><strong>Proposed dependency form</strong>: Developers must justify new packages</p>
</li>
<li><p><strong>Bundle impact analysis</strong>: Automated testing of bundle size impact</p>
</li>
<li><p><strong>Alternatives checklist</strong>: Documented consideration of lighter options</p>
</li>
<li><p><strong>Regular audits</strong>: Monthly dependency reviews</p>
</li>
</ol>
<p>We added bundle size budgets to our CI pipeline:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// package.json</span>
{
  <span class="hljs-string">"bundlesize"</span>: [
    {
      <span class="hljs-string">"path"</span>: <span class="hljs-string">"./dist/main.*.js"</span>,
      <span class="hljs-string">"maxSize"</span>: <span class="hljs-string">"250 kB"</span>
    },
    {
      <span class="hljs-string">"path"</span>: <span class="hljs-string">"./dist/vendors.*.js"</span>,
      <span class="hljs-string">"maxSize"</span>: <span class="hljs-string">"700 kB"</span>
    }
  ]
}
</code></pre>
<p>This process has prevented at least seven unnecessary dependencies from entering our codebase in the three months since implementation.</p>
<ol start="6">
<li><strong>Compression &amp; Caching Strategies</strong></li>
</ol>
<p>Beyond dependency optimization, we implemented several network-level optimizations:</p>
<ul>
<li><p><strong>Brotli compression</strong>: We replaced gzip with Brotli, which provides ~11% better compression</p>
</li>
<li><p><strong>Long-term caching</strong>: Set far-future cache headers (1 year) with content-based hashing</p>
</li>
<li><p><strong>CDN-hosted dependencies</strong>: Used public CDNs for common libraries when appropriate</p>
</li>
<li><p><strong>Preloading critical assets</strong>: Implemented <code>&lt;link rel="preload"&gt;</code> for essential resources</p>
</li>
</ul>
<p>These changes further reduced perceived load times by optimizing how resources were delivered to users, complementing our bundle size reductions.</p>
<h3 id="heading-the-results-before-and-after-analysis">The results: Before and After Analysis</h3>
<p>The final results, measured using Lighthouse, WebPageTest, and our internal analytics platform, exceeded even our stretch goals:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*xYwKwNVoQ_b_E7fin67mYQ.png" alt="Before &amp; After Analysis" /></p>
<p>Beyond the performance metrics, we saw several unexpected benefits:</p>
<ul>
<li><p><strong>Faster build times</strong>: CI builds went from 8 minutes to under 4 minutes</p>
</li>
<li><p><strong>Fewer bugs</strong>: Removing complex dependencies eliminated subtle integration issues</p>
</li>
<li><p><strong>Improved developer experience</strong>: The codebase became more understandable and maintainable</p>
</li>
</ul>
<h2 id="heading-13-webpack-optimization-tips-you-should-know">13 Webpack Optimization Tips You Should Know</h2>
<p>I will share some of my commonly used techniques from these aspects:</p>
<ul>
<li><p>Improving the building speed</p>
</li>
<li><p>Reducing the size of the packaged files</p>
</li>
<li><p>Improving the user experience.</p>
</li>
</ul>
<h3 id="heading-improving-the-building-speed">Improving the Building Speed</h3>
<ol>
<li><strong>thread-loader</strong></li>
</ol>
<p>Multithreading can improve the efficiency of the program; we can also use it in Webpack. And <code>thread-loader</code> is a loader that can enable multi-threading in Webpack.</p>
<p>Installation of the loader:</p>
<pre><code class="lang-typescript">npm i thread-loader -D
</code></pre>
<p>Configuration:</p>
<pre><code class="lang-typescript">{
        test: <span class="hljs-regexp">/\.js$/</span>,
        use: [
          <span class="hljs-string">'thread-loader'</span>,
          <span class="hljs-string">'babel-loader'</span>
        ],
}
</code></pre>
<ol start="2">
<li><strong>cache-loader</strong></li>
</ol>
<p>In the process of deploying our project, Webpack needs to build the project several times. To speed up subsequent builds, we can use caching. The cache-related loader is cache-loader.</p>
<p>Installation:</p>
<pre><code class="lang-typescript">npm i cache-loader -D
</code></pre>
<p>Configuration:</p>
<pre><code class="lang-typescript">{
        test: <span class="hljs-regexp">/\.js$/</span>,
        use: [
          <span class="hljs-string">'cache-loader'</span>,
          <span class="hljs-string">'thread-loader'</span>,
          <span class="hljs-string">'babel-loader'</span>
        ],
}
</code></pre>
<ol start="3">
<li><strong>Hot update</strong></li>
</ol>
<p>When we modify a file in a project, Webpack will rebuild the entire project by default, but this is not necessary. We only need to recompile this file, which is more efficient; this strategy is called a hot update.</p>
<p>Webpack has a built-in hot update plugin; we just need to enable hot update in the configuration.</p>
<p>Configuration:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// import webpack</span>
<span class="hljs-keyword">const</span> webpack = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack'</span>);
</code></pre>
<p>then:</p>
<pre><code class="lang-typescript">{
  plugins: [
      <span class="hljs-keyword">new</span> webpack.HotModuleReplacementPlugin()
  ],

  devServer: {
      hot: <span class="hljs-literal">true</span>
  }
}
</code></pre>
<ol start="4">
<li><strong>exclude &amp; include</strong></li>
</ol>
<p>In our project, some files and folders never need to participate in the build. So we can specify these files in the configuration file to prevent Webpack from retrieving them, thereby improving compilation efficiency.</p>
<p>Of course, we can also specify that some files need to be compiled.</p>
<ul>
<li><p><code>exclude</code> : files that don’t need to be compiled</p>
</li>
<li><p><code>include</code> : files that need to be compiled</p>
</li>
</ul>
<p>Configuration:</p>
<pre><code class="lang-typescript">{
    test: <span class="hljs-regexp">/\.js$/</span>,

    include: path.resolve(__dirname, <span class="hljs-string">'../src'</span>),

    exclude: <span class="hljs-regexp">/node_modules/</span>,    use: [
        <span class="hljs-string">'babel-loader'</span>
    ]
}
</code></pre>
<h3 id="heading-reducing-the-size-of-the-packaged-files">Reducing the size of the packaged files</h3>
<ol start="5">
<li><strong>Minify CSS code</strong></li>
</ol>
<p><code>css-minimizer-webpack-plugin</code> can compress and deduplicate CSS code.</p>
<p>Installation:</p>
<pre><code class="lang-typescript">npm i css-minimizer-webpack-plugin -D
</code></pre>
<p>Configuration:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> CssMinimizerPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'css-minimizer-webpack-plugin'</span>)
</code></pre>
<p>and:</p>
<pre><code class="lang-typescript">optimization: {
    minimizer: [
      <span class="hljs-keyword">new</span> CssMinimizerPlugin(),
    ],
  }
</code></pre>
<ol start="6">
<li><strong>Minify JavaScript code</strong></li>
</ol>
<p><code>terser-webpack-plugin</code> can compress and deduplicate JavaScript code.</p>
<p>Installation:</p>
<pre><code class="lang-typescript">npm i terser-webpack-plugin -D
</code></pre>
<p>Configuration:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> TerserPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'terser-webpack-plugin'</span>)optimization: {
    minimizer: [
      <span class="hljs-keyword">new</span> CssMinimizerPlugin(), 
      <span class="hljs-keyword">new</span> TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: <span class="hljs-literal">true</span>, <span class="hljs-comment">// remove console statement</span>
          },
        },
      }),
    ],
  }
</code></pre>
<ol start="7">
<li><strong>tree-sharking</strong></li>
</ol>
<p>Tree-sharking is: to compile only that code that is actually used, not the code that is not used in the project.</p>
<p>In Webpack 5, tree-shaking is enabled by default. You just need to make sure to use production mode when final compiling.</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  mode: <span class="hljs-string">'production'</span>
}
</code></pre>
<ol start="8">
<li><strong>source-map</strong></li>
</ol>
<p>When there is a bug in our code, source-map can help us quickly locate the location in our source code. But this file is huge.</p>
<p>In order to balance performance and accuracy, we should: generate a more accurate (but larger) source map in development mode; generate a smaller (but not as accurate) source map in production mode.</p>
<p>Development mode:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  mode: <span class="hljs-string">'development'</span>,
  devtool: <span class="hljs-string">'eval-cheap-module-source-map'</span>
}
</code></pre>
<p>Production mode:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  mode: <span class="hljs-string">'production'</span>,
  devtool: <span class="hljs-string">'nosources-source-map'</span>
}
</code></pre>
<ol start="9">
<li><strong>Bundle Analyzer</strong></li>
</ol>
<p>We can use <code>webpack-bundle-analyzer</code> to review the column of the bundle file after packaging, and then perform corresponding volume optimization.</p>
<p>Installation:</p>
<pre><code class="lang-typescript">npm i webpack-bundle-analyzer -D
</code></pre>
<p>Configuration:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> {
  BundleAnalyzerPlugin
} = <span class="hljs-built_in">require</span>(<span class="hljs-string">'webpack-bundle-analyzer'</span>)<span class="hljs-comment">// config</span>
plugins: [
    <span class="hljs-keyword">new</span> BundleAnalyzerPlugin(),
]
</code></pre>
<h3 id="heading-improving-the-user-experience">Improving the user experience</h3>
<ol start="10">
<li><strong>Module Lazy Loading</strong></li>
</ol>
<p>If the module is not lazy-loaded, the code of the entire project will be packaged into one JS file, resulting in a very large size of a single JS file. Then, when the user requests the webpage, the loading time of the first screen will be longer.</p>
<p>After module lazy loading, the large JS file will be divided into multiple small JS files, and the webpage will be loaded on demand when loading, which greatly improves the loading speed of the first screen.</p>
<p>To enable lazy loading, we just need to write code like this:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/router/index.jsconst routes = [</span>
  {
    path: <span class="hljs-string">'/login'</span>,
    name: <span class="hljs-string">'login'</span>,
    component: login
  },
  {
    path: <span class="hljs-string">'/home'</span>,
    name: <span class="hljs-string">'home'</span>,    <span class="hljs-comment">// lazy-load</span>
    component: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../views/home/home.vue'</span>),
  },
]
</code></pre>
<ol start="11">
<li><strong>Gzip</strong></li>
</ol>
<p>Gzip is a common algorithm for compressing files, which can improve transmission efficiency. However, this function requires back-end cooperation.</p>
<p>Installation:</p>
<pre><code class="lang-typescript">npm i compression-webpack-plugin -D
</code></pre>
<p>Configuration:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">const</span> CompressionPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'compression-webpack-plugin'</span>)
<span class="hljs-comment">// config</span>
plugins: [

    <span class="hljs-comment">// gzip</span>
    <span class="hljs-keyword">new</span> CompressionPlugin({
      algorithm: <span class="hljs-string">'gzip'</span>,
      threshold: <span class="hljs-number">10240</span>,
      minRatio: <span class="hljs-number">0.8</span>
    })
  ]
</code></pre>
<ol start="12">
<li><strong>base64</strong></li>
</ol>
<p>For some small pictures, they can be converted into base64 encoding, which can reduce the number of HTTP requests for users and improve the user experience. <code>url-loader</code> has been deprecated in webpack5, we can use <code>asset-module</code> instead.</p>
<p>Configuration:</p>
<pre><code class="lang-typescript">{
   test: <span class="hljs-regexp">/\.(png|jpe?g|gif|svg|webp)$/</span>,
   <span class="hljs-keyword">type</span>: <span class="hljs-string">'asset'</span>,
   parser: {      <span class="hljs-comment">// Conditions for converting to base64</span>
      dataUrlCondition: {
         maxSize: <span class="hljs-number">25</span> * <span class="hljs-number">1024</span>, <span class="hljs-comment">// 25kb</span>
      }
   },
   generator: {
    filename: <span class="hljs-string">'images/[contenthash][ext][query]'</span>,
   },
},
</code></pre>
<ol start="13">
<li><strong>Properly configure the hash</strong></li>
</ol>
<p>We can add a hash to the bundle file, which makes it easier to handle caching.</p>
<pre><code class="lang-typescript">output: {
    path: path.resolve(__dirname, <span class="hljs-string">'../dist'</span>),
    filename: <span class="hljs-string">'js/chunk-[contenthash].js'</span>,
    clean: <span class="hljs-literal">true</span>,
  },
</code></pre>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*YEDS1z_VHVAPL_beMIfHaA.png" alt /></p>
<h2 id="heading-how-to-fully-optimize-webpack-4-tree-shaking">How to Fully Optimize Webpack 4 Tree Shaking</h2>
<p>Before going into technical details, let me summarize the benefits. Different applications will see different levels of benefits with this exercise. The main deciding factor is the amount of dead, tree-sharkable code in your application. If you don’t have much, then you won’t see much of a benefit from tree-sharking. We had a lot of dead code in ours.</p>
<p>In our department, the biggest problem was a number of shared libraries. These ranged from simple homegrown component libraries to corporate standard component libraries to giant blobs of code shoved together into a library for no rhyme or reason. A lot of it is tech debt, but a big problem was that all of our applications were importing all of these libraries, when in reality each one only needed small pieces of them.</p>
<p>Overall, once tree-shaking was implemented, our applications shrank from between 25% to 75%, depending on the application. The average reduction across all of them was 52%, primarily driven by these bloated shared libraries being the majority of the code in small applications.</p>
<h3 id="heading-what-is-considered-dead-code">What is considered Dead Code?</h3>
<p>This is the simple: It’s code that Webpack can’t see you using. Webpack follows the trail of import/export statements throughout the application, so if it sees something being imported but ultimately not being used, it considers that to be “dead code“ and will tree-shake it.</p>
<p>Dead code isn’t always clear, though. Below will be a few examples of dead code vs “live” code, which I hope will make this more clear. Keep in mind that there will be cases where Webpack will see something as dead code even though it really isn’t. Please see the section on Side Effects to learn how to handle this.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Importing, assigning to a JavaScript object, and using it in the code below</span>
<span class="hljs-comment">// This is considered "live" code and will NOT be tree-shaken</span>
<span class="hljs-keyword">import</span> Stuff <span class="hljs-keyword">from</span> <span class="hljs-string">'./stuff'</span>;
doSomething(Stuff);
<span class="hljs-comment">// Importing, assigning to a JavaScript object, but NOT using it in the code below</span>
<span class="hljs-comment">// This is considered "dead" code and will be tree shaken</span>
<span class="hljs-keyword">import</span> Stuff <span class="hljs-keyword">from</span> <span class="hljs-string">'./stuff'</span>;
doSomething();
<span class="hljs-comment">// Importing but not assigning to a JavaScript object and not using it in the code</span>
<span class="hljs-comment">// This is considered to be "dead" code and will be tree shaken</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./stuff'</span>;
doSomething();
<span class="hljs-comment">// Importing an entire library, but not assigning to a JavaScript object and not using it in the code</span>
<span class="hljs-comment">// Oddly enough, this is considered to be "live" code, as Webpack treats library imports differently from local code imports</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'my-lib'</span>;
doSomething();
</code></pre>
<h3 id="heading-writing-tree-shakable-imports">Writing Tree-Shakable Imports</h3>
<p>When writing tree-shakable code, your imports are important. You should avoid importing entire libraries into a single JavaScript object. When you do so, you are telling Webpack that you need the whole library, and Webpack will not tree-shake it.</p>
<p>Take this example from the popular library Lodash. Importing the entire library at once is a big NO, but importing individual pieces is much better. Of course, Lodash specifically needs other steps to be tree-shaken, but this is a good first step.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Import everything (NOT TREE-SHAKABLE)</span>
<span class="hljs-keyword">import</span> _ <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash'</span>;
<span class="hljs-comment">// Import named export (CAN BE TREE SHAKEN)</span>
<span class="hljs-keyword">import</span> { debounce } <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash'</span>;
<span class="hljs-comment">// Import the item directly (CAN BE TREE SHAKEN)</span>
<span class="hljs-keyword">import</span> debounce <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash/lib/debounce'</span>;
</code></pre>
<p>Check out <a target="_blank" href="https://medium.com/@craigmiller160/how-to-fully-optimize-webpack-4-tree-shaking-405e1c76038">this article</a> to figure out more techniques about tree shaking.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://sayanmondal342.medium.com/the-what-why-and-how-of-javascript-bundlers-f617f82aa09a">https://sayanmondal342.medium.com/the-what-why-and-how-of-javascript-bundlers-f617f82aa09a</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/bundler-behind-the-scenes-of-your-crafted-frontend-code-rendering-in-users-browser-411d7b7d5e29">https://levelup.gitconnected.com/bundler-behind-the-scenes-of-your-crafted-frontend-code-rendering-in-users-browser-411d7b7d5e29</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/the-battle-of-bundlers-6333a4e3eda9">https://medium.com/better-programming/the-battle-of-bundlers-6333a4e3eda9</a></p>
<p><a target="_blank" href="https://blog.lyearn.com/how-webpack-works-236f8cc43ae7">https://blog.lyearn.com/how-webpack-works-236f8cc43ae7</a></p>
<p><a target="_blank" href="https://mvskiran.medium.com/the-core-concepts-of-webpack-customing-webpack-414483a86fb7">https://mvskiran.medium.com/the-core-concepts-of-webpack-customing-webpack-414483a86fb7</a></p>
<p><a target="_blank" href="https://medium.com/ekino-france/beyond-webpack-esbuild-vite-rollup-swc-and-snowpack-97911a7175cf">https://medium.com/ekino-france/beyond-webpack-esbuild-vite-rollup-swc-and-snowpack-97911a7175cf</a></p>
<p><a target="_blank" href="https://rahuulmiishra.medium.com/exploring-four-core-concepts-every-frontend-developer-should-know-b51f6e0e1cd2">https://rahuulmiishra.medium.com/exploring-four-core-concepts-every-frontend-developer-should-know-b51f6e0e1cd2</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/6-webpack-concepts-for-advanced-react-developers-d016da2cad52">https://medium.com/better-programming/6-webpack-concepts-for-advanced-react-developers-d016da2cad52</a></p>
<p><a target="_blank" href="https://blog.bitsrc.io/why-frontend-developers-need-to-be-webpack-experts-32e734b6f04a">https://blog.bitsrc.io/why-frontend-developers-need-to-be-webpack-experts-32e734b6f04a</a></p>
<p><a target="_blank" href="https://www.developerway.com/posts/webpack-and-yarn-magic-against-duplicates-in-bundles">https://www.developerway.com/posts/webpack-and-yarn-magic-against-duplicates-in-bundles</a></p>
<p><a target="_blank" href="https://medium.com/the-syntax-diaries/the-hidden-cost-of-npm-dependencies-how-we-cut-bundle-size-by-70-overnight-4d913fcf9dde">https://medium.com/the-syntax-diaries/the-hidden-cost-of-npm-dependencies-how-we-cut-bundle-size-by-70-overnight-4d913fcf9dde</a></p>
<p><a target="_blank" href="https://medium.com/frontend-canteen/13-webpack-optimization-tips-you-should-know-668666f8c020">https://medium.com/frontend-canteen/13-webpack-optimization-tips-you-should-know-668666f8c020</a></p>
]]></content:encoded></item><item><title><![CDATA[Git Handbook]]></title><description><![CDATA[When developing software, we find ourselves with the need to manage the changes that are being made in the code, and when working as a team, all team members always have a copy of this code in which they can work and, later, integrate these changes. ...]]></description><link>https://blog.tuanhadev.tech/git-handbook</link><guid isPermaLink="true">https://blog.tuanhadev.tech/git-handbook</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Git]]></category><category><![CDATA[Git Commands]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Tue, 13 May 2025 10:55:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/KPAQpJYzH0Y/upload/f0e1f651b5df0dc91a65db8ae331d4ad.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When developing software, we find ourselves with the need to manage the changes that are being made in the code, and when working as a team, all team members always have a copy of this code in which they can work and, later, integrate these changes. To facilitate this work, we have version control systems, which allow us to track and manage changes that occur in the code over time: for this, we are going to see the use of and the workflow with GitFlow.</p>
<p>Git is a version control software developed by Linus Torvalds (the creator of Linux), in order to coordinate the work with his collaborators.</p>
<p>Keep in mind that Git has a distributed architecture, so instead of the code being in a single place, when a developer makes a working copy of this code, it generates a repository that can contain the full history of changes that have been made in that code.</p>
<h1 id="heading-repository-revision-commit-some-vocabulary">Repository, revision, commit… Some vocabulary</h1>
<p>When working with Git and version control, we come across a series of terms that it is necessary to know what they are.</p>
<ul>
<li><p><strong>Branch:</strong> A branch is a separate line of development in your project. It allows you to work on new features or fixes without affecting the main codebase.</p>
</li>
<li><p><strong>Checkout:</strong> The <code>git checkout</code> command is used to switch between branches or restore files to a previous state.</p>
</li>
<li><p><strong>Clone:</strong> <code>git clone</code> creates a full local copy of a remote repository, including its history, branches, and files.</p>
</li>
<li><p><strong>Commit:</strong> A commit is a snapshot of your changes. It includes a message describing what was done, along with metadata like author and date.</p>
</li>
<li><p><strong>Conflict:</strong> A conflict happens when Git cannot automatically merge changes from different sources. You'll need to manually resolve these.</p>
</li>
<li><p><strong>Diff (Difference):</strong> A diff shows what has changed between two versions of a file or set of files — additions, deletions, or modifications.</p>
</li>
<li><p><strong>HEAD:</strong> <code>HEAD</code> refers to the latest commit on the current branch you're working on.</p>
</li>
<li><p><strong>Merge:</strong> <code>git merge</code> integrates changes from one branch into another. Often used to bring feature branches into the main branch.</p>
</li>
<li><p><strong>Pull:</strong> <code>git pull</code> fetches and merges updates from a remote repository into your local branch.</p>
</li>
<li><p><strong>Pull Request (PR):</strong> A request to merge your changes into another branch, often reviewed before approval. Commonly used in collaborative workflows.</p>
</li>
<li><p><strong>Push:</strong> <code>git push</code> uploads your local commits to a remote repository to share with others.</p>
</li>
<li><p><strong>Repository (Repo):</strong> A storage location for your project code and history. Can be local or remote (e.g., GitHub).</p>
</li>
<li><p><strong>Tag:</strong> A tag marks a specific point in your project’s history, often used for releases (e.g., <code>v1.0.0</code>).</p>
</li>
<li><p><strong>Staging Area (Index):</strong> The place where files go when you run <code>git add</code>. Only staged files are included in the next commit.</p>
</li>
<li><p><strong>Fork:</strong> A personal copy of someone else's repository, typically used to propose changes or contribute to the original project.</p>
</li>
<li><p><strong>Rebase:</strong> <code>git rebase</code> moves or combines commits to a new base commit. Helps keep a clean, linear project history.</p>
</li>
<li><p><strong>Revert:</strong> <code>git revert</code> creates a new commit that undoes the effects of a previous commit.</p>
</li>
<li><p><strong>Reset:</strong> <code>git reset</code> changes your current branch’s history. It can remove commits or unstage files depending on the flags used.</p>
</li>
<li><p><strong>Stash:</strong> <code>git stash</code> temporarily saves uncommitted changes so you can work on something else, then come back to them later.</p>
</li>
<li><p><strong>Origin:</strong> The default name for the remote repository you cloned from. Used to refer to it in Git commands (e.g., <code>git push origin main</code>).</p>
</li>
<li><p><strong>Blame:</strong> <code>git blame</code> shows which commit and author last modified each line of a file. Useful for tracking down when and why a line was changed.</p>
</li>
<li><p><strong>Cherry-pick:</strong> <code>git cherry-pick</code> allows you to apply a specific commit from one branch onto another. Helpful when you want to copy just one change instead of merging everything.</p>
</li>
<li><p><strong>Hook:</strong> Git hooks are scripts that run automatically before or after certain events (like committing or pushing). Used for tasks like code formatting, testing, or enforcing rules.</p>
</li>
<li><p><strong>Submodule:</strong> A Git repository inside another Git repository. Useful for managing dependencies or separate components in a project.</p>
</li>
<li><p><strong>Upstream:</strong> Refers to the remote branch that your local branch is tracking. For example, if you're working on a feature branch that is based on <code>origin/main</code>, then <code>origin/main</code> is the upstream.</p>
</li>
<li><p><strong>Detached HEAD:</strong> A state where your <code>HEAD</code> points to a specific commit instead of a branch. You're not on any branch, so commits won’t be saved to any branch unless you explicitly create one.</p>
</li>
<li><p><strong>Fast-forward Merge:</strong> A type of merge that doesn’t require a merge commit. Git just moves the pointer forward because there were no divergent changes.</p>
</li>
<li><p><strong>Squash:</strong> The process of combining multiple commits into one. Often used before merging to keep history clean.</p>
</li>
<li><p><strong>Tracking Branch:</strong> A local branch that is set to track a remote branch. This allows you to easily pull/push without specifying the remote and branch name every time.</p>
</li>
<li><p><strong>Worktree:</strong> A working tree (or worktree) is a directory with a checkout of a branch. Git allows multiple worktrees linked to one repository—useful for working on multiple branches at once.</p>
</li>
</ul>
<h1 id="heading-git-advanced-concepts">Git Advanced Concepts</h1>
<p><a target="_blank" href="https://github.com/mike-rambil/Advanced-Git">https://github.com/mike-rambil/Advanced-Git</a></p>
<h2 id="heading-what-is-inside-git-folder">What is inside <code>.Git</code> Folder?</h2>
<h3 id="heading-the-moment-of-truth-opening-git"><strong>The Moment of Truth: Opening .git</strong></h3>
<p>Here's what most developers think <code>.git</code> contains: "Uh... git stuff?"</p>
<p>Let me show you what's actually in there. Open any git repository and run:</p>
<pre><code class="lang-javascript">ls -la .git/
</code></pre>
<p>You'll see something like this:</p>
<pre><code class="lang-javascript">.git/
├── HEAD
├── config
├── description
├── hooks/
├── index
├── info/
├── objects/
├── refs/
└── logs/
</code></pre>
<p>Each piece has a purpose. Each file tells a story. Let's decode them one by one.</p>
<p><strong>The Directory Structure</strong></p>
<p>Before we dive deep, here's the map:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Path</td><td>What It Does</td></tr>
</thead>
<tbody>
<tr>
<td><code>HEAD</code></td><td>Points to your current branch</td></tr>
<tr>
<td><code>config</code></td><td>Repository-specific settings</td></tr>
<tr>
<td><code>description</code></td><td>Used by GitWeb (rarely used)</td></tr>
<tr>
<td><code>hooks/</code></td><td>Scripts that run on git events</td></tr>
<tr>
<td><code>index</code></td><td>Your staging area (binary file)</td></tr>
<tr>
<td><code>info/</code></td><td>Global exclude patterns</td></tr>
<tr>
<td><code>objects/</code></td><td><strong>All your data lives here</strong></td></tr>
<tr>
<td><code>refs/</code></td><td>Pointers to commits (branches, tags)</td></tr>
<tr>
<td><code>logs/</code></td><td>History of ref changes (reflog)</td></tr>
</tbody>
</table>
</div><p>The two most important directories? <strong>objects/</strong> and <strong>refs/</strong>. Everything else is supporting infrastructure.</p>
<h3 id="heading-head-your-location-marker">HEAD: Your Location Marker</h3>
<p>Let's start simple. Check what's in <code>HEAD</code>:</p>
<pre><code class="lang-javascript">cat .git/HEAD
</code></pre>
<p>Output:</p>
<pre><code class="lang-javascript">ref: refs/heads/main
</code></pre>
<p>That's it. That's the file. <strong>HEAD is just a pointer</strong> telling Git which branch you're on. When you run <code>git checkout feature-branch</code>, Git rewrites this file:</p>
<pre><code class="lang-javascript">ref: refs/heads/feature-branch
</code></pre>
<p>When you check out a specific commit (detached HEAD state), it changes to:</p>
<pre><code class="lang-javascript">a3f2d8b9c1e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8
</code></pre>
<p><strong>Mind-blowing realization #1:</strong> Your "current branch" is just a text file containing a reference.</p>
<h3 id="heading-refs-where-branches-live">refs/: Where Branches Live</h3>
<p>Look inside the <code>refs</code> directory:</p>
<pre><code class="lang-javascript">tree .git/refs/
</code></pre>
<pre><code class="lang-javascript">.git/refs/
├── heads/
│   ├── main
│   ├── feature-auth
│   └── bugfix-login
├── remotes/
│   └── origin/
│       ├── main
│       └── develop
└── tags/
    └── v1<span class="hljs-number">.0</span><span class="hljs-number">.0</span>
</code></pre>
<p>Each branch is <strong>just a file</strong> containing a commit hash. Let's prove it:</p>
<pre><code class="lang-javascript">cat .git/refs/heads/main
</code></pre>
<p>Output:</p>
<pre><code class="lang-javascript">f3e4d5c6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2
</code></pre>
<p>That's your latest commit on <code>main</code>. That's literally what a branch is—a 40-character hash pointing to a commit.</p>
<p><strong>When you create a new branch:</strong></p>
<pre><code class="lang-javascript">git branch feature-<span class="hljs-keyword">new</span>
</code></pre>
<p>Git creates <code>.git/refs/heads/feature-new</code> and copies the current commit hash into it. That's it. No magic.</p>
<p><strong>Mind-blowing realization #2:</strong> Branches are just files with commit hashes. Creating a branch is almost free because it's just writing 40 bytes to a file.</p>
<h3 id="heading-objects-gits-time-machine">objects/: Git's Time Machine</h3>
<p>This is where the real magic happens. The <code>objects/</code> directory is Git's database—every commit, every file, every version you've ever created lives here.</p>
<pre><code class="lang-javascript">ls .git/objects/
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-number">00</span>/  <span class="hljs-number">0</span>f/  <span class="hljs-number">1</span>a/  <span class="hljs-number">2</span>b/  <span class="hljs-number">3</span>c/  <span class="hljs-number">4</span>d/  <span class="hljs-number">5</span>e/  <span class="hljs-number">6</span>f/  <span class="hljs-number">7</span>a/  <span class="hljs-number">8</span>b/  <span class="hljs-number">9</span>c/  ...
info/  pack/
</code></pre>
<p>Those two-character directories? They're organizing objects by their hash prefix (for performance). Let's look deeper:</p>
<pre><code class="lang-javascript">ls .git/objects/a3/
</code></pre>
<pre><code class="lang-javascript">f2d8b9c1e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8
</code></pre>
<p>Combine the directory name with the filename: <code>a3f2d8b9c1e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8</code></p>
<p>That's a complete SHA-1 hash. But what is it?</p>
<p><strong>What's a Git Object?</strong></p>
<p>Git stores everything as objects. There are only four types:</p>
<ol>
<li><p><strong>Blob</strong> - File contents</p>
</li>
<li><p><strong>Tree</strong> - Directory structure</p>
</li>
<li><p><strong>Commit</strong> - Snapshot in time</p>
</li>
<li><p><strong>Tag</strong> - Named reference (annotated tags)</p>
</li>
</ol>
<p>You can inspect any object:</p>
<pre><code class="lang-javascript">git cat-file -t a3f2d8b9  # Type
git cat-file -p a3f2d8b9  # Content
</code></pre>
<p><strong>The Three Types of Objects</strong></p>
<p>Let's see them in action. I'll create a simple file and commit it:</p>
<pre><code class="lang-javascript">echo <span class="hljs-string">"Hello Git"</span> &gt; test.txt
git add test.txt
git commit -m <span class="hljs-string">"Add test file"</span>
</code></pre>
<p>Now let's follow the trail.</p>
<h4 id="heading-1-the-commit-object"><strong>1. The Commit Object</strong></h4>
<pre><code class="lang-javascript">git cat-file -p HEAD
</code></pre>
<p>Output:</p>
<pre><code class="lang-javascript">tree <span class="hljs-number">5e8</span>b9c0d1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6
parent f3e4d5c6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2
author John Doe &lt;john@example.com&gt; <span class="hljs-number">1733654400</span> +<span class="hljs-number">0000</span>
committer John Doe &lt;john@example.com&gt; <span class="hljs-number">1733654400</span> +<span class="hljs-number">0000</span>

Add test file
</code></pre>
<p>The commit points to a <strong>tree</strong> (the directory structure) and has metadata (author, timestamp, message).</p>
<h4 id="heading-2-the-tree-object"><strong>2. The Tree Object</strong></h4>
<pre><code class="lang-javascript">git cat-file -p <span class="hljs-number">5e8</span>b9c0d1a2b
</code></pre>
<p>Output:</p>
<pre><code class="lang-javascript"><span class="hljs-number">100644</span> blob a3f2d8b9c1e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8    test.txt
<span class="hljs-number">100644</span> blob <span class="hljs-number">7</span>a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6    README.md
<span class="hljs-number">040000</span> tree b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7    src/
</code></pre>
<p>The tree lists files (blobs) and subdirectories (trees). It's like a snapshot of <code>ls -l</code>.</p>
<h4 id="heading-3-the-blob-object"><strong>3. The Blob Object</strong></h4>
<pre><code class="lang-javascript">git cat-file -p a3f2d8b9c1e4
</code></pre>
<p>Output:</p>
<pre><code class="lang-javascript">Hello Git
</code></pre>
<p>The blob is <strong>just the file contents</strong>. No filename, no metadata—pure content.</p>
<p><strong>Mind-blowing realization #3:</strong> Git doesn't store diffs. It stores complete snapshots. Every commit points to a full tree of all files.</p>
<p><strong>Following the Chain</strong></p>
<p>Here's how it connects:</p>
<pre><code class="lang-javascript">HEAD
  ↓
refs/heads/main (contains: f3e4d5c6...)
  ↓
Commit f3e4d5c6...
  ├── tree <span class="hljs-number">5e8</span>b9c0d...
  │     ├── blob a3f2d8b9... (test.txt)
  │     ├── blob <span class="hljs-number">7</span>a8b9c0d... (README.md)
  │     └── tree b9c0d1e2... (src/)
  └── parent e2f3a4b5... (previous commit)
</code></pre>
<p>When you run <code>git log</code>, Git walks this chain backwards through parent commits.</p>
<h3 id="heading-index-the-staging-area-revealed">index: The Staging Area Revealed</h3>
<p>The staging area isn't virtual—it's a binary file:</p>
<pre><code class="lang-javascript">file .git/index
</code></pre>
<p>Output:</p>
<pre><code class="lang-javascript">.git/index: Git index, version <span class="hljs-number">2</span>, <span class="hljs-number">3</span> entries
</code></pre>
<p>When you run <code>git add</code>, Git:</p>
<ol>
<li><p>Creates a blob object for the file</p>
</li>
<li><p>Updates the index to point to that blob</p>
</li>
<li><p>Doesn't create a commit yet</p>
</li>
</ol>
<p>You can peek inside (it's binary, but git can read it):</p>
<pre><code class="lang-javascript">git ls-files --stage
</code></pre>
<p>Output:</p>
<pre><code class="lang-javascript"><span class="hljs-number">100644</span> a3f2d8b9c1e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8 <span class="hljs-number">0</span>   test.txt
<span class="hljs-number">100644</span> <span class="hljs-number">7</span>a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6 <span class="hljs-number">0</span>    README.md
</code></pre>
<p>Each entry shows: permissions, blob hash, stage number, and filename.</p>
<p><strong>Mind-blowing realization #4:</strong> <code>git add</code> creates the object immediately. The staging area is just a list of "these blobs should be in the next commit."</p>
<h3 id="heading-config-your-repository-settings">config: Your Repository Settings</h3>
<p>Open <code>.git/config</code>:</p>
<pre><code class="lang-javascript">cat .git/config
</code></pre>
<pre><code class="lang-javascript">[core]
    repositoryformatversion = <span class="hljs-number">0</span>
    filemode = <span class="hljs-literal">true</span>
    bare = <span class="hljs-literal">false</span>
    logallrefupdates = <span class="hljs-literal">true</span>

[remote <span class="hljs-string">"origin"</span>]
    url = git@github.com:username/repo.git
    fetch = +refs/heads<span class="hljs-comment">/*:refs/remotes/origin/*

[branch "main"]
    remote = origin
    merge = refs/heads/main

[user]
    name = John Doe
    email = john@example.com</span>
</code></pre>
<p>This is where <code>git config --local</code> writes settings. Global settings live in <code>~/.gitconfig</code>, but repository-specific overrides live here.</p>
<p>Want to change your email for just this project?</p>
<pre><code class="lang-javascript">git config user.email <span class="hljs-string">"work@company.com"</span>
</code></pre>
<p>Check the file—it's been updated.</p>
<h3 id="heading-hooks-automation-paradise">hooks/: Automation Paradise</h3>
<p>The <code>hooks/</code> directory contains scripts that run automatically on git events:</p>
<pre><code class="lang-javascript">ls .git/hooks/
</code></pre>
<pre><code class="lang-javascript">applypatch-msg.sample
pre-commit.sample
pre-push.sample
prepare-commit-msg.sample
post-commit.sample
...
</code></pre>
<p>Remove the <code>.sample</code> extension to activate a hook. For example, create <code>.git/hooks/pre-commit</code>:</p>
<pre><code class="lang-javascript">#!<span class="hljs-regexp">/bin/</span>bash
# Run tests before every commit

npm test
<span class="hljs-keyword">if</span> [ $? -ne <span class="hljs-number">0</span> ]; then
    echo <span class="hljs-string">"Tests failed! Commit aborted."</span>
    exit <span class="hljs-number">1</span>
fi
</code></pre>
<p>Make it executable:</p>
<pre><code class="lang-javascript">chmod +x .git/hooks/pre-commit
</code></pre>
<p>Now every <code>git commit</code> runs your tests first. If they fail, the commit is blocked.</p>
<p><strong>Popular hooks:</strong></p>
<ul>
<li><p><code>pre-commit</code> - Lint code, run tests</p>
</li>
<li><p><code>commit-msg</code> - Enforce commit message format</p>
</li>
<li><p><code>pre-push</code> - Run full test suite before pushing</p>
</li>
<li><p><code>post-merge</code> - Install dependencies after pulling</p>
</li>
</ul>
<p><strong>Mind-blowing realization #5:</strong> Git is programmable. You can automate almost anything.</p>
<h3 id="heading-logs-gits-diary">logs/: Git's Diary</h3>
<p>The <code>logs/</code> directory tracks every change to refs:</p>
<pre><code class="lang-javascript">cat .git/logs/HEAD
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-number">0000000</span> a3f2d8b John Doe &lt;john@example.com&gt; <span class="hljs-number">1733654400</span> +<span class="hljs-number">0000</span>    commit (initial): Initial commit
a3f2d8b f3e4d5c John Doe &lt;john@example.com&gt; <span class="hljs-number">1733654500</span> +<span class="hljs-number">0000</span>    commit: Add test file
f3e4d5c e2f3a4b John Doe &lt;john@example.com&gt; <span class="hljs-number">1733654600</span> +<span class="hljs-number">0000</span>    commit: Update README
</code></pre>
<p>This is what powers <code>git reflog</code>—a safety net that remembers where you've been, even if you've deleted branches or reset commits.</p>
<p><strong>Accidentally deleted a branch?</strong></p>
<pre><code class="lang-javascript">git reflog
# Find the commit hash before you deleted it
git checkout -b recovered-branch a3f2d8b
</code></pre>
<p>The reflog saved you.</p>
<h3 id="heading-a-real-world-scenario-following-a-commit"><strong>A Real-World Scenario: Following a Commit</strong></h3>
<p>Let's put it all together. You run:</p>
<pre><code class="lang-javascript">git commit -m <span class="hljs-string">"Fix login bug"</span>
</code></pre>
<p>Here's what Git does behind the scenes:</p>
<ol>
<li><p><strong>Creates blob objects</strong> for each file in the index</p>
</li>
<li><p><strong>Creates a tree object</strong> representing the directory structure</p>
</li>
<li><p><strong>Creates a commit object</strong> pointing to:</p>
<ul>
<li><p>The tree</p>
</li>
<li><p>The parent commit</p>
</li>
<li><p>Author metadata</p>
</li>
<li><p>Commit message</p>
</li>
</ul>
</li>
<li><p><strong>Updates the branch ref</strong> (<code>.git/refs/heads/main</code>) to point to the new commit</p>
</li>
<li><p><strong>Updates HEAD</strong> (if needed)</p>
</li>
<li><p><strong>Logs the change</strong> in <code>.git/logs/refs/heads/main</code></p>
</li>
</ol>
<p>All of this happens in milliseconds. And it's just file operations—no database, no network calls.</p>
<p><strong>Why This Matters</strong></p>
<p>Understanding <code>.git</code> changes how you use Git:</p>
<p><strong>Before:</strong> "I'll just run these commands and hope it works."</p>
<p><strong>After:</strong></p>
<ul>
<li><p>"I need to recover a deleted branch—I'll check reflog."</p>
</li>
<li><p>"I want to automate linting—I'll use pre-commit hooks."</p>
</li>
<li><p>"This merge conflict makes sense—Git is comparing tree objects."</p>
</li>
<li><p>"Branches are cheap—they're literally just pointers."</p>
</li>
</ul>
<p>You stop fearing Git and start leveraging it.</p>
<h3 id="heading-key-takeaways"><strong>Key Takeaways</strong></h3>
<ol>
<li><p><strong>Git is just files and directories</strong> - No magic, no mystery</p>
</li>
<li><p><strong>Branches are pointers</strong> - Creating them is nearly free</p>
</li>
<li><p><strong>Objects are immutable</strong> - Once created, they never change</p>
</li>
<li><p><strong>The staging area is real</strong> - It's <code>.git/index</code></p>
</li>
<li><p><strong>Everything is recoverable</strong> - Thanks to reflog and objects</p>
</li>
<li><p><strong>Git is hackable</strong> - Hooks let you automate workflows</p>
</li>
<li><p><strong>Commits store snapshots</strong> - Not diffs</p>
</li>
</ol>
<p>The next time you run <code>git init</code>, remember: you're not just initializing a repository. You're creating a time machine, a database, and an automation system—all stored in plain files.</p>
<h2 id="heading-git-flow">Git Flow</h2>
<p>Git Flow was created by Vincent Driessen in 2010. It is tailor-made for projects that thrive on structure, such as those with strict release cycles or large teams juggling multiple features. It provides a clear roadmap, guiding teams through development, testing, and production with ease. This structure helps everyone stay aligned and focused, avoiding confusion along the way.</p>
<p>What makes Git Flow truly special is its use of <strong>different types of branches</strong>, each with a unique role in the development journey. Think of it like roles in a movie: some branches are the stars, others work behind the scenes, but together, they create a masterpiece.</p>
<h3 id="heading-why-use-git-flow">Why Use Git Flow?</h3>
<p>Git Flow offers a high level of organization for managing software projects. Here are some reasons why teams might adopt Git Flow:</p>
<ul>
<li><p><strong>Clear Branching Model</strong>: It separates different types of work (features, releases, hotfixes), making it easier for teams to collaborate and understand what’s happening at each stage of the development process.</p>
</li>
<li><p><strong>Easy to Scale</strong>: Git Flow works well for large teams and projects where multiple developers need to work on features independently while maintaining a stable main branch.</p>
</li>
<li><p><strong>Release Management</strong>: It integrates well with release cycles and provides a clear path for creating and managing releases, from development to production.</p>
</li>
<li><p><strong>Supports Hotfixes</strong>: The hotfix strategy provides that urgent bugs can be addressed without disrupting the ongoing work in development.</p>
</li>
</ul>
<h3 id="heading-core-branches-in-git-flow">Core Branches in Git Flow</h3>
<p>Git Flow revolves around two primary branches that serve as the foundation of the repository. These branches represent the stable, ongoing development process and the production-ready codebase.</p>
<ol>
<li><strong>Main (or Master) Branch</strong></li>
</ol>
<p>This branch contains the stable production-ready code. It’s where the latest production releases are tagged, and it should always reflect the state of the project that is live in production. You should only merge into the <code>main</code> branch when you’re deploying to production. All releases are tagged with version numbers here (e.g., <code>v1.0.0</code>, <code>v1.1.0</code>). Typically, it’s named <code>main</code> or <code>master</code>, depending on your preference or the Git provider’s default.</p>
<ol start="2">
<li><strong>Develop Branch</strong></li>
</ol>
<p>This branch serves as the integration branch for ongoing development. It holds all the code that’s been merged and tested and is considered the most up-to-date version of the next release. Developers commit their changes to feature branches, and once they are finished, they merge them into <code>develop</code>. When the code in <code>develop</code> is stable and ready for release, it will be merged into the <code>main</code> branch. By default, this branch is named <code>develop</code>.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*QqcO8oyjKyWCbwPa5QwyTA.png" alt /></p>
<h3 id="heading-supporting-branches-in-git-flow">Supporting Branches in Git Flow</h3>
<p>Git Flow also uses supporting branches to manage specific tasks like new features, releases, and hotfixes. These are where most of the action happens during the development cycle.</p>
<ol>
<li><strong>Feature Branches</strong></li>
</ol>
<p>These branches are used to develop new features or changes. Feature branches are typically created off the <code>develop</code> branch and are merged back into <code>develop</code> once the feature is complete. Feature branches are named according to the feature being developed, e.g., <code>feature/user-authentication</code> or <code>feature/payment-gateway</code>. This helps easily identify the purpose of each branch.</p>
<ul>
<li><p>When starting a new feature, create a branch from <code>develop</code>.</p>
</li>
<li><p>Work on the feature and commit changes regularly.</p>
</li>
<li><p>Once complete, merge the feature back into the <code>develop</code> branch.</p>
</li>
</ul>
<p>After a feature is merged, it is important to rebase the feature branch with <code>develop</code> to guarantee there are no conflicts.</p>
<ol start="2">
<li><strong>Release Branches</strong></li>
</ol>
<p>When a certain set of features is ready for release, but additional testing, bug fixes, or preparation for deployment is needed, a release branch is created. This branch helps isolate the final stages of development from ongoing feature work in <code>develop</code>. Typically named <code>release/1.0.0</code>, <code>release/2.0.0</code>, etc., based on the version number of the release.</p>
<ul>
<li><p>When <code>develop</code> is stable and ready for release, a release branch is created.</p>
</li>
<li><p>The release branch is used for last-minute fixes, preparing documentation, and adjusting configuration files.</p>
</li>
<li><p>After testing, the release branch is merged into both <code>main</code> (for deployment) and <code>develop</code> (to ensure any final changes are reflected in future development).</p>
</li>
</ul>
<p>Once the release is completed and merged into <code>main</code>, it’s tagged with the release version (e.g., <code>v1.0.0</code>). It is then merged back into <code>develop</code> to provide any changes made during the release process are incorporated into the ongoing development.</p>
<ol start="3">
<li><strong>Hotfix Branches</strong></li>
</ol>
<p>Hotfixes are used to quickly patch bugs in production. When critical issues are discovered in the <code>main</code> branch (e.g., security vulnerabilities or bugs affecting users), a hotfix branch is created from <code>main</code> to address the issue immediately. Typically named <code>hotfix/bug-fix</code>, e.g., <code>hotfix/security-patch</code>.</p>
<ul>
<li><p>A hotfix is created directly from the <code>main</code> branch.</p>
</li>
<li><p>The necessary changes have been made and committed to the hotfix branch.</p>
</li>
<li><p>Once the fix is complete, the hotfix branch is merged back into both <code>main</code> (for deployment) and <code>develop</code> (to secure future development, includes the fix.)</p>
</li>
</ul>
<p>Hotfixies are typically fast, providing a quick fix without disturbing ongoing feature development. Once merged, the hotfix branch is deleted.</p>
<h3 id="heading-git-flow-workflow-in-action">Git Flow Workflow in Action</h3>
<p>Here is an example of how a typical Git Flow workflow would unfold:</p>
<ol>
<li><p><strong>Start with a</strong> <code>develop</code> <strong>branch</strong>: This is the main development branch. All work begins here, with new features being developed in their own branches.</p>
</li>
<li><p><strong>Create a feature branch</strong> from <code>develop</code> for each new feature: Developers work on isolated branches for individual features or changes. Each branch is frequently merged back into <code>develop</code> after completing a feature.</p>
</li>
<li><p><strong>Create a release branch</strong> when <code>develop</code> is stable and ready for release. This branch prepares the code for production. It is used for final testing, bug fixes, and release-related tasks.</p>
</li>
<li><p><strong>Merge the release branch into</strong> <code>main</code> <strong>and tag it</strong>: Once the release branch is stable, it is merged into <code>main</code>, tagged with a version, and deployed.</p>
</li>
<li><p><strong>Create hotfixes</strong> if needed: If bugs are found in production, a hotfix branch is created directly from <code>main</code> to fix them.</p>
</li>
</ol>
<p>Git Flow provides clear guidelines for how to work on different types of changes and helps to ensure that the master branch always contains stable, tested code.</p>
<p>It’s important to note that Git Flow is one of the many branching models that can be used with Git, and it may not be the best fit for every team or project. It’s a great starting point for teams new to Git, but as the team and the project grow, it’s important to re-evaluate and see if it still fits the team’s needs.</p>
<h2 id="heading-comparing-git-branching-strategies"><strong>Comparing Git Branching Strategies</strong></h2>
<p>Picture this: You are leading a development team, and everyone is pushing code simultaneously. Without a clear branching strategy, your codebase becomes a tangled mess of conflicts, broken builds, and frustrated developers. Sound familiar? If you have ever found yourself in this situation, you are not alone.</p>
<p>A branching strategy is your team’s roadmap for managing code changes, collaborating effectively, and shipping quality software. It’s essentially a set of rules that guide how developers interact with a shared codebase, determining when to create branches, how to merge changes, and how to maintain code stability throughout the development process.</p>
<p>But it’s more than just rules. A good branching strategy aligns with how your team works your release cycles, QA workflows, CI/CD pipelines, and even how often you hotfix to production. Without one, you will likely end up firefighting merge conflicts during crunch time or accidentally pushing half-baked code to production.</p>
<p>In this section, we will break down the most popular branching strategies, when to use them, and how to pick the right one based on your team size, workflow, or development style. Whether you are building solo or working with a fast-moving squad, having a solid branching strategy will make collaboration smoother and releases far less painful.</p>
<h3 id="heading-why-your-team-needs-a-branching-strategy">Why Your Team Needs a Branching Strategy</h3>
<p>Think of branching strategies as traffic rules for your codebase. Without them, you are asking for chaos on the digital highway when your developers ship code every day.</p>
<p>Here’s why a solid branch strategy matters:</p>
<ul>
<li><p><strong>Enhanced Collaboration</strong>: Branching allows multiple developers to work simultaneously without stepping on each other’s toes. Each developer can create their own isolated workspace while staying connected to the main project. No more waiting for someone to finish a task before you can start yours.</p>
</li>
<li><p><strong>Risk Mitigation</strong>: By isolating new features, bug fixes, or experimental code in separate branches, you protect your main codebase from instability. Your production branch stays clean and deployable, while innovation continues safely in parallel.</p>
</li>
<li><p><strong>Organised Workflow</strong>: A well-defined branching model prevents the dreaded merge-hell, those nightmare situations where code conflicts pile up and break the build. It brings structure to how changes are integrated and released.</p>
</li>
<li><p><strong>Quality Control</strong>: Most branching strategies incorporate pull requests, reviews, and CI pipelines, making sure every change is reviewed and tested before being deployed to production. This leads to cleaner code, fewer bugs, and more confidence in every deploy.</p>
</li>
</ul>
<p>Let’s dive into the most popular branching strategies and see which one might be the perfect fit for your team.</p>
<h3 id="heading-gitflow">GitFlow</h3>
<p>Originally introduced by Vincent Driessen in 2010, <strong>GitFlow</strong> is one of the most structured and widely adopted branching strategies for managing complex projects. It’s designed around formal release cycles, making it a strong choice for teams that value process, stability, and long-term maintenance.</p>
<p><strong>How GitFlow Works</strong></p>
<p>GitFlow defines <strong>five core branches</strong>, each with a specific purpose:</p>
<ul>
<li><p><code>main</code> — Contains production-ready code. Every commit here is a stable release.</p>
</li>
<li><p><code>develop</code> — The integration branch where new features are merged before they’re ready to go live.</p>
</li>
<li><p><code>feature/*</code> — For building out new functionality. Branches off from <code>develop</code> and merges back into it.</p>
</li>
<li><p><code>release/*</code> — Used to prep a new version for production. Created from <code>develop</code> and eventually merged into both <code>main</code> and <code>develop</code>.</p>
</li>
<li><p><code>hotfix/*</code> — For urgent fixes on production. Created from <code>main</code>, then merged back into both <code>main</code> and <code>develop</code>.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757418340261/65820cb7-ba7a-4342-b3a2-82224918ac7c.webp" alt class="image--center mx-auto" /></p>
<p><strong>When To Use GitFlow</strong></p>
<p>GitFlow is a great fit if:</p>
<ul>
<li><p>Your team follows scheduled release cycles.</p>
</li>
<li><p>You need to maintain multiple versions (e.g., patch v1.x while working on v2.x).</p>
</li>
<li><p>You have formal QA or staging environments.</p>
</li>
<li><p>Your project has complex release management or compliance requirements.</p>
</li>
</ul>
<p><strong>Props of GitFlow</strong></p>
<ul>
<li><p>Clear separation of concerns across features, releases, and hotfixes</p>
</li>
<li><p>Ideal for parallel development across different product versions</p>
</li>
<li><p>Structured workflow enforces discipline and quality control</p>
</li>
<li><p>Predictable release cycles with designed staging periods</p>
</li>
</ul>
<p><strong>Cons of GitFlow</strong></p>
<ul>
<li><p>Adds complexity, not ideal for small teams or fast-moving startups</p>
</li>
<li><p>Not suited for continuous deployment: GitHub Flow or trunk-based is better for that.</p>
</li>
<li><p>Can result in long-lived branches, increasing the risk of merge conflicts</p>
</li>
<li><p>Slows down delivery due to multiple approval stages and manual coordination</p>
</li>
</ul>
<p>GitFlow is powerful, but it’s a heavyweight. If your team thrives on structure and you manage multiple release versions, GitFlow will serve you well. But, if speed and simplicity are your top priorities, consider something leaner.</p>
<h3 id="heading-github-flow">GitHub Flow</h3>
<p>If GitFlow is all about structure and process, GitHub Flow is its minimalist cousin. This strategy keeps things simple, just one main branch and short-lived feature branches. It is designed for teams that ship fast and often, especially those embracing continuous deployment.</p>
<p><strong>How GitHub Flow Works</strong></p>
<p>This workflow is refreshingly straightforward.</p>
<ol>
<li><p>Create a <strong>feature branch</strong> from <code>main</code></p>
</li>
<li><p>Push commits to the feature branch</p>
</li>
<li><p>Open a <strong>pull request</strong> for code review and automated tests</p>
</li>
<li><p>Once approved, <strong>merge back to</strong> <code>main</code></p>
</li>
<li><p>Deploy immediately (optional but encouraged)</p>
</li>
</ol>
<p>Everything in <code>main</code> should always be production-ready.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757419546638/65725ad7-976a-458c-a69a-ccec1ad729ff.webp" alt class="image--center mx-auto" /></p>
<p><strong>When To Use GitHub Flow</strong></p>
<p>GitHub Flow is ideal if:</p>
<ul>
<li><p>Your team practices continuous deployment</p>
</li>
<li><p>You have strong automated testing in place</p>
</li>
<li><p>You ship frequently, small releases</p>
</li>
<li><p>You are working in a small to mid-sized team.</p>
</li>
</ul>
<p><strong>Props of Github Flow</strong></p>
<ul>
<li><p>Simple and intuitive to adapt, with no complex branching rules</p>
</li>
<li><p>Perfect for rapid iteration and a fast feedback loop.</p>
</li>
<li><p>Plays well with CI/CD pipelines</p>
</li>
<li><p>Encourages frequent integration, reducing big-bang mergers.</p>
</li>
</ul>
<p><strong>Cons of GitHub Flow</strong></p>
<ul>
<li><p>Not designed for multiple production versions or LTS support</p>
</li>
<li><p>In large teams, it can result in frequent merge conflicts</p>
</li>
<li><p>No formal release staging or QA branching</p>
</li>
<li><p>Requires strong test automation to avoid pushing bugs to production</p>
</li>
</ul>
<p>GitHub Flow is lean, fast, and DevOps-friendly. If your team values speed over ceremony and has good CI/CD hygiene, this model will feel like second nature.</p>
<h3 id="heading-gitlab-flow">GitLab Flow</h3>
<p>GitLab Flow is a hybrid strategy that builds on GitFlow and GitHub Flow but brings environments and development workflows into a mix. It was introduced by GitLab to better connect development branches with deployment environments, making it particularly useful in projects with a clear DevOps pipeline.</p>
<p><strong>How GitLab Flow works</strong></p>
<p><em>Production Branch Model</em></p>
<ul>
<li><p>Developers create feature branches from <code>main</code> or <code>develop</code></p>
</li>
<li><p>Merge back into the mainline when complete</p>
</li>
<li><p>Tag releases and deploy from <code>main</code> to environments</p>
</li>
</ul>
<p><em>Environment-Based Model</em></p>
<ul>
<li><p>Each environment (e.g. <code>pre-prod</code>, <code>staging</code>, <code>production</code>) has a dedicated branch</p>
</li>
<li><p>Merges promote changes from lower to higher environments</p>
</li>
</ul>
<p>You can also combine this with <strong>issue tracking</strong>, where branches directly map to issues or epics (<code>feature/123-login-page</code>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757421260550/be63e222-df90-41c0-800d-c4879183e60f.webp" alt class="image--center mx-auto" /></p>
<p><strong>When to Use GitLab Flow</strong></p>
<ul>
<li><p>You want to map branches to environments or deployments</p>
</li>
<li><p>You use GitLab CI/CD pipelines and want to keep them tightly integrated</p>
</li>
<li><p>Your team needs flexibility, but also structure between releases</p>
</li>
</ul>
<p><strong>Pros of GitLab Flow</strong></p>
<ul>
<li><p>Tightly integrates with CI/CD and DevOps tooling</p>
</li>
<li><p>Supports both continuous delivery and versioned releases</p>
</li>
<li><p>Encourages better traceability (commits linked to issues, merges to environments)</p>
</li>
</ul>
<p><strong>Cons of GitLab Flow</strong></p>
<ul>
<li><p>It can be confusing for beginners due to multiple models</p>
</li>
<li><p>Needs strict discipline to avoid inconsistencies across the environment branches</p>
</li>
</ul>
<p>GitLab Flow is highly adaptable and DevOps-friendly. If you use GitLab and want your Git branching to reflect your deployment lifecycle, this is your go-to.</p>
<h3 id="heading-environment-branching">Environment Branching</h3>
<p><strong>Environment Branching</strong> is a strategy where each deployment environment (like <code>dev</code>, <code>qa</code>, <code>staging</code>, <code>prod</code>) has its branch. Teams using this model push code from one environment branch to the next as it progresses through the pipeline.</p>
<p><strong>How Environment Branching Works</strong></p>
<ul>
<li><p>Developers work on <code>dev</code>, test on <code>qa</code>, stabilise in <code>staging</code>, and deploy from <code>prod</code></p>
</li>
<li><p>Promotions happen via merging between branches:<br />  <code>dev</code> → <code>qa</code> → <code>staging</code> → <code>prod</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757421338214/4b06d22f-8604-48b4-a034-f7082090dbba.webp" alt class="image--center mx-auto" /></p>
<p><strong>When to Use Environment Branching</strong></p>
<ul>
<li><p>You’re working with legacy systems or manual promotion processes</p>
</li>
<li><p>Your CI/CD tooling is limited or non-existent</p>
</li>
<li><p>You want full control over what gets pushed to each environment</p>
</li>
</ul>
<p><strong>Pros of Environment Branching</strong></p>
<ul>
<li><p>Very explicit control over deployments</p>
</li>
<li><p>Simple to understand in legacy or manual release workflows</p>
</li>
</ul>
<p><strong>Cons of Environment Branching</strong></p>
<ul>
<li><p>High risk of divergence between environments</p>
</li>
<li><p>Code may behave differently in each branch if not carefully synchronised</p>
</li>
<li><p>Difficult to scale with modern CI/CD practices</p>
</li>
<li><p>Anti-pattern in most modern DevOps setups</p>
</li>
</ul>
<p>Environment Branching gives you control, but at a cost. It’s rarely recommended for modern teams and should generally be avoided unless necessary.</p>
<h3 id="heading-trunk-based-development">Trunk-Based Development</h3>
<p><strong>Trunk-Based Development (TBD)</strong> is the go-to strategy for high-performing engineering teams that deploy multiple times a day. It’s simple at the surface but demands real discipline underneath. The idea? Everyone works off a single branch, no long-lived branches, no complex release trees. Just fast commits and faster feedback.</p>
<p><strong>How Trunk-Based Development Works</strong></p>
<p>There’s one main branch, often called <code>main</code> or <code>trunk</code>. All development happens here.</p>
<ul>
<li><p>Developers commit directly to <code>main</code>, often <strong>multiple times per day</strong>.</p>
</li>
<li><p>Changes are small, incremental, and backed by <strong>automated tests</strong>.</p>
</li>
<li><p>Incomplete features are hidden behind <strong>feature flags</strong>, so code can ship without being user-visible.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757421408284/08430a2a-75fd-4065-b68c-85c44e095a8a.webp" alt class="image--center mx-auto" /></p>
<p><strong>When to Use Trunk-Based Development</strong></p>
<p>This strategy works best if:</p>
<ul>
<li><p>Your team follows continuous integration religiously.</p>
</li>
<li><p>You have a strong automated testing setup (unit + integration + end-to-end).</p>
</li>
<li><p>You’re building SaaS products or anything that updates frequently.</p>
</li>
<li><p>Your team is experienced with feature flagging and CI/CD tools.</p>
</li>
</ul>
<p><strong>Pros of Trunk-Based Development</strong></p>
<ul>
<li><p>No more painful merges, everyone works on the same code path.</p>
</li>
<li><p>Encourages true continuous integration and early bug discovery.</p>
</li>
<li><p>Delivers the fastest feedback loops from dev to prod.</p>
</li>
<li><p>Simplifies the workflow, no juggling of multiple active branches.</p>
</li>
</ul>
<p><strong>Cons of Trunk-Based Development</strong></p>
<ul>
<li><p>Requires robust testing to avoid breaking production.</p>
</li>
<li><p>Not ideal for large, monolithic features (unless they’re behind flags).</p>
</li>
<li><p>You’ll need to manage feature flags carefully to avoid technical debt.</p>
</li>
<li><p>Demands a high level of discipline across the team — sloppy commits will hurt.</p>
</li>
</ul>
<p>Trunk-Based Development is fast, clean, and CI/CD friendly, but it’s not for the faint of heart. If your team is mature, test-driven, and ships frequently, TBD can supercharge your workflow.</p>
<h3 id="heading-release-branching">Release Branching</h3>
<p>If your product has long-term users, multiple versions in the wild, and strict release schedules, <strong>Release Branching</strong> is your secret weapon. This strategy helps you isolate each major release so you can squash bugs, patch security issues, and ship updates without slowing down future development.</p>
<p><strong>How Release Branching Works</strong></p>
<p>The idea is simple:</p>
<ul>
<li><p>When you’re ready to stabilise a version for release, <strong>create a release branch</strong> from your mainline (<code>main</code> or <code>develop</code>).</p>
</li>
<li><p>All <strong>bug fixes and release-specific tweaks</strong> go into this branch.</p>
</li>
<li><p>Meanwhile, the <code>main</code> branch stays open for <strong>ongoing feature development</strong>.</p>
</li>
<li><p>Once the release is finalised, it gets <strong>tagged and deployed</strong>, and if needed, hotfixes can be applied directly to this release branch.</p>
</li>
</ul>
<p>Example branches might look like: <code>release/v2.0</code>, <code>release/v2.1.1</code>, etc.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757421475626/d2904dbe-b928-4798-99de-8bb32eb1bd3e.webp" alt class="image--center mx-auto" /></p>
<p><strong>When to Use Release Branching</strong></p>
<p>You’ll benefit from this model if:</p>
<ul>
<li><p>You support multiple product versions simultaneously (e.g., v1.x, v2.x).</p>
</li>
<li><p>Your releases are tied to deadlines (quarterly, client-based, etc.).</p>
</li>
<li><p>You need to provide long-term support or hotfixes for older versions.</p>
</li>
<li><p>You have a formal stabilisation and QA process before every release.</p>
</li>
</ul>
<p><strong>Pros of Release Branching</strong></p>
<ul>
<li><p>Clean isolation between feature development and stabilisation work.</p>
</li>
<li><p>Supports parallel development and maintenance efforts.</p>
</li>
<li><p>Great for version tracking and rollback in production environments.</p>
</li>
<li><p>Ideal for products that require long-term support (LTS).</p>
</li>
</ul>
<p><strong>Cons of Release Branching</strong></p>
<ul>
<li><p>It can get complex with many active branches to maintain.</p>
</li>
<li><p>Requires disciplined merge practices to sync fixes back into <code>main</code>.</p>
</li>
<li><p>Easy to fall into branch proliferation, where every minor version lives forever.</p>
</li>
</ul>
<p>Release Branching gives you control and stability across versions. It’s not the fastest strategy, but for teams juggling support and innovation, it brings much-needed order.</p>
<h3 id="heading-feature-branching">Feature Branching</h3>
<p><strong>Feature Branching</strong> is probably the most widely used and easiest-to-understand strategy. It’s the default mental model for most developers — create a branch for each new piece of work, build in isolation, and merge back when you’re done. Simple, effective, and foundational to many modern Git workflows.</p>
<p><strong>How Feature Branching Works</strong></p>
<ul>
<li><p>Start by branching off from <code>main</code> (or <code>develop</code>) to work on a specific feature or bug fix.</p>
</li>
<li><p>You commit changes to this branch until the work is complete.</p>
</li>
<li><p>Once reviewed and tested, the branch is merged back — typically via a <strong>pull request</strong>.</p>
</li>
<li><p>Branches are usually named like <code>feature/login-form</code> or <code>bugfix/payment-error</code>.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757421569573/b7788411-9b84-489f-b356-2027f0a82545.webp" alt class="image--center mx-auto" /></p>
<p><strong>When to Use Feature Branching</strong></p>
<p>Feature Branching is a solid choice when:</p>
<ul>
<li><p>Your team is new to Git workflows and needs a gentle learning curve.</p>
</li>
<li><p>You want to isolate features or experiments without risk to mainline stability.</p>
</li>
<li><p>You value clear ownership of features or fixes.</p>
</li>
<li><p>Your project has medium complexity, without too many parallel changes.</p>
</li>
</ul>
<p><strong>Pros of Feature Branching</strong></p>
<ul>
<li><p>Provides clear isolation between features, reducing the risk of accidental interference.</p>
</li>
<li><p>Super easy to adopt and understand, great for onboarding teams.</p>
</li>
<li><p>Encourages better code reviews through pull request workflows.</p>
</li>
<li><p>Offers a flexible foundation that can scale into more advanced strategies (like Git Flow or GitHub Flow).</p>
</li>
</ul>
<p><strong>Cons of Feature Branching</strong></p>
<ul>
<li><p>It can result in long-lived branches if not merged frequently.</p>
</li>
<li><p>Integration challenges arise when multiple feature branches are merged after diverging for too long.</p>
</li>
<li><p>Potential for merge conflicts, especially on fast-moving teams with overlapping work areas.</p>
</li>
</ul>
<p>Feature Branching is the go-to starting point for most teams. It offers clarity and control, but needs discipline to avoid merge headaches down the road.</p>
<h3 id="heading-forking-workflow">Forking Workflow</h3>
<p>When you’re running an open source project, letting just anyone push to the main repo isn’t an option. That’s where the <strong>Forking Workflow</strong> comes in. It’s built for scale, safety, and distributed collaboration, which is why it’s the default model used on GitHub for open source contributions.</p>
<p><strong>How Forking Workflow Works</strong></p>
<ul>
<li><p>A contributor <strong>forks</strong> the main repository, creating their copy on the server (usually GitHub).</p>
</li>
<li><p>They <strong>clone their fork locally</strong>, create a feature or fix branch, and commit changes.</p>
</li>
<li><p>Once ready, they <strong>open a pull request</strong> back to the original repository (commonly called <code>upstream</code>).</p>
</li>
<li><p>Maintainers review, request changes, and decide whether to merge.</p>
</li>
</ul>
<p>This model gives project maintainers <strong>full control</strong> while still allowing anyone to contribute.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757421681773/d085e1be-3c79-476e-8d35-4229b02a1415.webp" alt class="image--center mx-auto" /></p>
<p><strong>When to Use Forking Workflow</strong></p>
<p>Consider forking if:</p>
<ul>
<li><p>You’re running an open-source project with external contributors.</p>
</li>
<li><p>You want strict control over what enters the main codebase.</p>
</li>
<li><p>Your team is distributed or made up of untrusted/external developers.</p>
</li>
<li><p>You expect a high volume of pull requests from the community.</p>
</li>
</ul>
<p><strong>Pros of Forking Workflow</strong></p>
<ul>
<li><p>No write access required for contributors, keeps your main branch safe.</p>
</li>
<li><p>Full control stays with project maintainers.</p>
</li>
<li><p>Scales beautifully with large numbers of contributors.</p>
</li>
<li><p>The de facto standard for open source collaboration.</p>
</li>
</ul>
<p><strong>Cons of Forking Workflow</strong></p>
<ul>
<li><p>Slightly more complex setup for new contributors (fork, clone, sync, pull request).</p>
</li>
<li><p>Overkill for small, trusted internal teams adds unnecessary friction.</p>
</li>
<li><p>Requires understanding of <code>origin</code> vs <code>upstream</code> remotes, which can trip up beginners.</p>
</li>
</ul>
<p>Forking Workflow is purpose-built for open source. It trades simplicity for control and security, exactly what you need when anyone on the internet can submit code.</p>
<h3 id="heading-choosing-the-right-strategy-for-your-team">Choosing the Right Strategy for Your Team</h3>
<p>Picking the right branching strategy isn’t a one-size-fits-all decision. It depends on how your team works, what you’re building, and how often you ship.</p>
<p>Here are some key factors to guide your choice:</p>
<p><strong>Team Size</strong></p>
<ul>
<li><p><strong>Small teams (2–5 developers)</strong>: GitHub Flow or Trunk-Based Development tends to work best, fewer branches, faster iteration.</p>
</li>
<li><p><strong>Larger teams</strong>: GitFlow or Release Branching provides the structure needed for coordination, especially across multiple squads.</p>
</li>
</ul>
<p><strong>Release Frequency</strong></p>
<ul>
<li><p><strong>Deploying daily or multiple times per day?</strong> Go with GitHub Flow or Trunk-Based; they’re designed for speed.</p>
</li>
<li><p><strong>Shipping on a schedule (e.g., quarterly releases)?</strong> GitFlow or Release Branching gives you the stability and process control you need.</p>
</li>
</ul>
<p><strong>Product Complexity</strong></p>
<ul>
<li><p><strong>Simple apps or MVPs</strong>: Keep it lightweight with GitHub Flow.</p>
</li>
<li><p><strong>Complex, enterprise-grade systems</strong>: Benefit from GitFlow’s or Release Branching’s separation of concerns.</p>
</li>
</ul>
<p><strong>Team Experience</strong></p>
<ul>
<li><p><strong>New teams</strong>: Start with Feature Branching or GitHub Flow — simple and easy to grasp.</p>
</li>
<li><p><strong>Mature teams</strong>: Can evolve toward Trunk-Based or GitFlow as tooling and CI/CD processes mature.</p>
</li>
</ul>
<p><strong>Compliance Requirements</strong></p>
<ul>
<li>If you’re in a <strong>regulated industry</strong> (finance, healthcare, etc.), you’ll likely need the <strong>formal approval gates</strong> and documentation trail offered by GitFlow or Release Branching.</li>
</ul>
<p>For more detailed explanations about the difference between those branching strategies. Check out those articles: <a target="_blank" href="https://medium.com/thedevproject/comparing-git-branching-strategies-git-flow-vs-github-flow-vs-gitlab-flow-2e1dd28be103">Comparing Git Branching Strategies</a>, <a target="_blank" href="https://medium.com/@technicadil_001/collaborative-git-workflows-gitflow-github-flow-and-trunk-based-development-dc77da145e3e">Collaborative Git Workflows</a></p>
<h2 id="heading-the-only-git-branching-strategy-that-works-in-real-teams"><strong>The Only Git Branching Strategy That Works in Real Teams</strong></h2>
<p>After years of messy merges, broken main branches, and endless “quick fixes,” I’ve found one branching model that consistently works — not in theory, but in real-world engineering teams with deadlines, pressure, and humans.</p>
<h3 id="heading-introduction-every-team-thinks-they-have-a-git-strategy-until-they-dont">Introduction: Every Team Thinks They Have a Git Strategy — Until They Don’t</h3>
<p>If you’ve worked on even one engineering team in your life, you already know this:<br />Git chaos isn’t caused by Git.<br />It’s caused by people.</p>
<p>Developers forget to rebase.<br />Long-lived branches drift for weeks.<br />Hotfixes magically appear in production without making it to <code>main</code>.<br />Someone merges half-finished work because “the sprint was ending anyway.”</p>
<p>And yet, every team proudly claims they “follow GitFlow,” or they “do trunk-based development,” or they “use feature branches with pull requests.” In practice? Most teams follow a chaotic cocktail of all three — sprinkled with confusion, tribal knowledge, and Slack messages like:</p>
<blockquote>
<p><em>“Wait, which branch should I open the PR against?”</em></p>
</blockquote>
<p>After a decade of working across startups, agencies, enterprise teams, and open-source projects, I’ve seen one branching strategy succeed more consistently than anything else:</p>
<p>👉 <strong>Short-Lived Feature Branches + a Protected Main Branch + Continuous Integration</strong></p>
<p>It sounds almost… disappointingly simple.<br />But it works — because it respects developer habits, real-world constraints, and the natural messiness of software teams.</p>
<p>Let’s break it down.</p>
<h3 id="heading-why-complex-branching-models-fail-in-real-teams">Why Complex Branching Models Fail in Real Teams</h3>
<p>Before we talk about what works, we need to talk about what fails — because the “why” is what makes the “how” stick.</p>
<ol>
<li><strong>GitFlow is great on paper and miserable in reality</strong></li>
</ol>
<p>GitFlow gives you:</p>
<ul>
<li><p>A <code>develop</code> branch</p>
</li>
<li><p>A <code>main</code> branch</p>
</li>
<li><p>Feature branches</p>
</li>
<li><p>Release branches</p>
</li>
<li><p>Hotfix branches</p>
</li>
<li><p>Occasional existential crisis branches</p>
</li>
</ul>
<p>The idea is to isolate work and organize releases.<br />The reality? Teams struggle to keep everything in sync.</p>
<p>Most GitFlow projects slowly devolve into:</p>
<ul>
<li><p>“Where does this go again?”</p>
</li>
<li><p>“Did we merge this into <code>develop</code> or only into <code>main</code>?"</p>
</li>
<li><p>“Why is the release branch 45 commits behind?”</p>
</li>
</ul>
<p>The overhead is too high. The cognitive load is too high.<br />And when a branching model requires this much discipline, it collapses.</p>
<ol start="2">
<li><strong>Trunk-Based Development fails when teams don’t have instant CI</strong></li>
</ol>
<p>In true trunk-based development (TBD):</p>
<ul>
<li><p>Everyone commits to <code>main</code> daily</p>
</li>
<li><p>Very small batches</p>
</li>
<li><p>Strict CI gating</p>
</li>
<li><p>Feature flags everywhere</p>
</li>
</ul>
<p>This works if you’re Google.<br />Or Netflix.<br />Or any team with god-tier tooling.</p>
<p>But in normal teams?</p>
<ul>
<li><p>PR reviews take time</p>
</li>
<li><p>CI pipelines are slow</p>
</li>
<li><p>Partially complete work can’t be safely merged</p>
</li>
<li><p>Everyone fears “breaking main”</p>
</li>
</ul>
<p>So developers start creating temporary branches…<br />which become long-lived branches…<br />which breaks TBD.</p>
<ol start="3">
<li><strong>Long-lived branches kill velocity every single time</strong></li>
</ol>
<p>The longer a branch lives, the more painful it becomes:</p>
<ul>
<li><p>Bigger PRs</p>
</li>
<li><p>More merge conflicts</p>
</li>
<li><p>More forgotten context</p>
</li>
<li><p>More code that “looked fine last week”</p>
</li>
</ul>
<p>This is how you get The Merge From Hell™.</p>
<p>Nothing slows teams down more reliably.</p>
<h3 id="heading-the-branching-strategy-that-actually-works">The Branching Strategy That Actually Works</h3>
<p>Here it is — the model I’ve seen succeed across 30+ teams:</p>
<blockquote>
<p><strong><em>Short-lived feature branches → Pull Request → CI checks → Merge to a fully protected</em></strong> <code>main</code> <strong><em>→ Deploy automatically.</em></strong></p>
</blockquote>
<p>Some call it “Feature Branching.”<br />Some call it a “lightweight GitHub Flow.”<br />I call it “The Only Strategy Humans Can Follow.”</p>
<p>Let’s break it into parts.</p>
<ol>
<li><strong>A Single Source of Truth:</strong> <code>main</code></li>
</ol>
<p><code>main</code> isn't just another branch.<br />It’s <strong>The Branch No One Touches</strong>.</p>
<p>Rules:</p>
<ul>
<li><p>No direct pushes</p>
</li>
<li><p>Only merge via pull requests</p>
</li>
<li><p>All merges must pass CI</p>
</li>
<li><p>All merges must pass at least one code review</p>
</li>
<li><p><code>main</code> always deployable</p>
</li>
</ul>
<p>If <code>main</code> is always stable, everything else becomes simpler:</p>
<ul>
<li><p>Releases are predictable</p>
</li>
<li><p>Hotfixes are trivial</p>
</li>
<li><p>Rollbacks are instant</p>
</li>
<li><p>Developers trust the codebase</p>
</li>
</ul>
<p>A safe <code>main</code> creates a less anxious engineering culture.</p>
<ol start="2">
<li><strong>Short-Lived Feature Branches</strong></li>
</ol>
<p>Every task — big or small — gets a branch:</p>
<pre><code class="lang-javascript">feature/login-page
bugfix/payment-timeout
chore/refactor-header
experiment/<span class="hljs-keyword">new</span>-cache
</code></pre>
<p>The branch lives for <strong>days, not weeks</strong>.</p>
<p>Why this works:</p>
<ul>
<li><p>Easy PR reviews</p>
</li>
<li><p>Small changes minimize conflicts</p>
</li>
<li><p>Fast merges keep code fresh</p>
</li>
<li><p>Better psychological momentum (finishing things feels good)</p>
</li>
</ul>
<p>If a branch lives more than 5–7 days, it’s a smell.</p>
<ol start="3">
<li><strong>Frequent Sync with</strong> <code>main</code></li>
</ol>
<p>Don’t wait until the end to sync.</p>
<p>Developers should rebase or merge <code>main</code> frequently:</p>
<ul>
<li><p>Avoid huge conflicts</p>
</li>
<li><p>Stay up to date with teammate changes</p>
</li>
<li><p>Keep PRs small and clean</p>
</li>
</ul>
<p>Your pull request shouldn’t resurface 80 old commits from last month.</p>
<ol start="4">
<li><strong>Pull Requests with Real Discussions</strong></li>
</ol>
<p>PRs are where engineering culture happens.</p>
<p>A good PR is:</p>
<ul>
<li><p>Small</p>
</li>
<li><p>Focused</p>
</li>
<li><p>Contextual (what + why)</p>
</li>
<li><p>Easy to review in &lt;10 minutes</p>
</li>
</ul>
<p>A bad PR is:</p>
<ul>
<li><p>900 lines</p>
</li>
<li><p>Multiple unrelated changes</p>
</li>
<li><p>Described with “minor fixes”</p>
</li>
<li><p>Reviewed only when someone gets tired of waiting</p>
</li>
</ul>
<p>PRs should be treated as collaborative conversations, not bureaucratic roadblocks.</p>
<ol start="5">
<li><strong>CI as the Uncompromising Gatekeeper</strong></li>
</ol>
<p>Humans are smart.<br />Git is smart.<br />Your CI pipeline is smarter.</p>
<p>Every PR must pass:</p>
<ul>
<li><p>Linting</p>
</li>
<li><p>Unit tests</p>
</li>
<li><p>Integration tests</p>
</li>
<li><p>Security checks</p>
</li>
<li><p>Build checks</p>
</li>
</ul>
<p>CI enforces discipline even when the team gets busy.</p>
<p>CI is the team member who never sleeps and never forgets.</p>
<ol start="6">
<li><strong>Automatic Deployment from</strong> <code>main</code></li>
</ol>
<p>This is the secret weapon.</p>
<p>Don’t create release branches.<br />Don’t manually cherry-pick fixes.<br />Don’t keep half-finished features hidden.</p>
<p>Just deploy <code>main</code>.</p>
<p>With this:</p>
<ul>
<li><p>Releases become boring (a good thing)</p>
</li>
<li><p>Hotfixes become trivial</p>
</li>
<li><p>Developers gain confidence</p>
</li>
</ul>
<p>If you want a release process:</p>
<ul>
<li><p>Tag versions (<code>v2.1.0</code>)</p>
</li>
<li><p>Maintain changelogs</p>
</li>
<li><p>Let automation handle the boring parts</p>
</li>
</ul>
<h3 id="heading-what-about-hotfixes">What About Hotfixes?</h3>
<p>Hotfixes are simple:</p>
<pre><code class="lang-javascript">hotfix/payment-crash
</code></pre>
<p>You branch from <code>main</code>, fix it, open a PR, merge, deploy.</p>
<p>Then — <strong>and this is the part most teams forget</strong> —<br />merge <code>main</code> back into any in-progress branches.</p>
<p>No more “the hotfix was never merged into develop.”</p>
<h3 id="heading-why-this-model-works-when-everything-else-fails">Why This Model Works When Everything Else Fails</h3>
<p>Simple:<br />It reduces cognitive load.</p>
<p>Most branching strategies fall apart because they assume developers will:</p>
<ul>
<li><p>Read long documentation</p>
</li>
<li><p>Follow complex rules</p>
</li>
<li><p>Remember obscure merge paths</p>
</li>
<li><p>Coordinate manually across teams</p>
</li>
</ul>
<p>This model succeeds because it works even when people are:</p>
<ul>
<li><p>Tired</p>
</li>
<li><p>Busy</p>
</li>
<li><p>Rushing a deadline</p>
</li>
<li><p>Switching between tasks</p>
</li>
<li><p>Joining mid-sprint</p>
</li>
<li><p>Working across time zones</p>
</li>
</ul>
<p>It’s the only model I’ve seen scale from 2-person startups to multi-team orgs without breaking.</p>
<h3 id="heading-how-to-transition-your-team-to-this-strategy">How to Transition Your Team to This Strategy</h3>
<p>Start with three simple rules:</p>
<p><strong>Rule 1: No one pushes to</strong> <code>main</code>. Ever.</p>
<p>Make it a protected branch.</p>
<p><strong>Rule 2: Every task gets a branch and a PR.</strong></p>
<p>Small, focused, easy to review.</p>
<p><strong>Rule 3: CI must pass before merging.</strong></p>
<p>Non-negotiable.</p>
<p>Then gradually introduce:</p>
<ul>
<li><p>Feature flags</p>
</li>
<li><p>Automatic deployments</p>
</li>
<li><p>Better test coverage</p>
</li>
<li><p>PR templates</p>
</li>
<li><p>Branch naming conventions</p>
</li>
</ul>
<p>Do it slowly.<br />Habits take time.</p>
<p>But the payoff is enormous.</p>
<h2 id="heading-automated-app-versioning">Automated App Versioning</h2>
<p>Imagine a software without versioning, any change to an application would be a chaotic leap into the unknown. Developers wouldn’t know if a new feature was added, a bug fixed, or if the application would ever run properly. Versioning provides clarity and structure, offering a roadmap for both developers and users.</p>
<p>In the intricate dance of versioning, each number tells a story, a story that extends beyond development and seamlessly interwines with the software testing cycle.</p>
<blockquote>
<p>Application versioning isn’t just a formality; it’s a strategic guide through the intricate phases of the software testing cycle. From alpha to release candidates (RC) and hotfixes, versioning ensures systematic testing and meticulous tracking of changes.</p>
</blockquote>
<h3 id="heading-why-does-versioning-matter">Why does versioning matter?</h3>
<p>Versioning serves as a critical foundation for a seamless and organized workflow. Here’s why it matters:</p>
<ol>
<li><p><strong>Traceability</strong>: Versioning provides a clear trail of changes, allowing teams to trace back and understand the evolution of the software.</p>
</li>
<li><p><strong>Communication</strong>: Clear version numbers act as a universal language, facilitating communication among developers, testers, and stakeholders.</p>
</li>
<li><p><strong>Coordination</strong>: Acts as a coordination mechanism, ensuring everyone involved is on the same page regarding the current state of the software.</p>
</li>
<li><p><strong>Testing Efficiency</strong>: In the testing lifecycle, versioning enables efficient testing by distinguishing between alpha, beta, and release candidates.</p>
</li>
<li><p><strong>Bug Tracking:</strong> Facilitates effective bug tracking, making it easier to identify when an issue was introduced and which changes are associated.</p>
</li>
<li><p><strong>Stability Assurance:</strong> Versioning helps ensure the stability of releases by clearly indicating backward-compatible and incompatible changes.</p>
</li>
</ol>
<p>Versioning, therefore, is not just a matter of differentiation between what is in the release and what is already deployed to production. It’s a strategic necessity in the ever-evolving realm of software development. It provides clarity, promotes collaboration, and enhances the overall efficiency of the development cycle.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1324/1*NCJdXgydHr5x_72bOXdjEg@2x.jpeg" alt /></p>
<h3 id="heading-semantic-versioning-semver-explained">Semantic Versioning (SemVer) Explained</h3>
<p>Semantic Versioning (SemVer) is a standardized versioning system that precisely communicates changes in the software release. The version number in SemVer comprises three segments: Major, Minor, and Patch.</p>
<ul>
<li><p><strong>Major Version (X.0.0):</strong> Significant, backward-incompatible changes. Incremented for breaking changes.</p>
</li>
<li><p><em>Example</em>: Current version: <strong>1.2.3</strong>, After breaking change: <strong>2.0.0</strong></p>
</li>
<li><p><strong>Minor Version (X.Y.0):</strong> Backward-compatible additions or enhancements. Incremented for new features.</p>
</li>
<li><p><em>Example</em>:Current version: <strong>1.2.3</strong>, After adding a feature: <strong>1.3.0</strong></p>
</li>
<li><p><strong>Patch Version (X.Y.Z):</strong> Backward-compatible bug fixes. Incremented for bug patches.</p>
</li>
<li><p><em>Example</em>:Current version: <strong>1.2.3,</strong> After fixing a bug: <strong>1.2.4</strong></p>
</li>
<li><p><strong>Pre-release Version:</strong> Identified by appending a hyphen and a series of dot-separated identifiers following the patch version. Denoted as “alpha,” “beta,” etc.</p>
</li>
<li><p><em>Example</em>: Alpha release: <strong>1.2.3-alpha.1,</strong> Beta release: <strong>1.2.3-beta.2</strong></p>
</li>
<li><p><strong>Numeric Metadata:</strong> Identified by appending a plus sign and a series of dot-separated numeric identifiers following the patch or pre-release version.Not considered for version precedence.</p>
</li>
<li><p><em>Example</em>: With numeric metadata: <strong>1.2.3-alpha.1+42</strong> . Basically used as a build number.</p>
</li>
</ul>
<p>Semantic Versioning enables clear communication about the nature of changes in the release, fostering predictability and ensuring compatibility across different versions of a software project.</p>
<p>Understanding Semantic Versioning aids in transparently conveying changes within a project. Now, check out <a target="_blank" href="https://levelup.gitconnected.com/automated-app-versioning-using-gitversion-gitflow-mandatory-practice-not-an-optional-2feb5c64c94f">this article</a> to explore how to seamlessly integrate SemVer into the Git Workflow using GitVersion.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*38Bw0JEsX2Z4gTiIfqSfgw@2x.jpeg" alt /></p>
<h2 id="heading-squash-commits">Squash Commits</h2>
<p>When you squash commits, you combine 2 or multiple commits into a single commit. This is useful when you have multiple small commits that are related to the same feature or fix, and you want to simplify your commit history. Squashing commits also makes it easier to review your changes and to track down bugs.</p>
<h3 id="heading-how-to-squash-commits">How to Squash Commits</h3>
<p>Here are the steps to squash commits in a git repository using the git CLI:</p>
<ol>
<li><p>Determine how many commits you want to squash. You can use the <code>git log</code> command to see a list of your commits and their hashes.</p>
</li>
<li><p>Use the <code>git rebase -i HEAD~N</code> command to open the interactive rebase tool, where <code>N</code> is the number of commits you want to squash.</p>
</li>
<li><p>In the text editor that opens, replace “pick” with “squash” or “fixup” for each commit you want to squash. “Squash” will combine the commit with the one before it, while “fixup” will combine the commit and discard its commit message.</p>
</li>
<li><p>Save and exit the editor by pressing <code>Ctrl + X</code>, then <code>Y</code>, and finally <code>Enter</code>.</p>
</li>
<li><p>If you have conflicts, resolve them by editing the conflicted files, staging the changes with <code>git add</code>, and then running <code>git rebase --continue</code>.</p>
</li>
<li><p>Force push the changes to the remote branch with <code>git push -f</code>.</p>
</li>
</ol>
<h2 id="heading-modern-git-commands">Modern Git Commands</h2>
<p>Git, however, introduced many features since then, and using them can make your life so much easier, so let’s explore some of the recently added, modern git commands that you should know about.</p>
<h3 id="heading-switch">Switch</h3>
<p>New since 2019, or more precisely, introduced Git version 2.23, is <code>git switch</code> which we can use to switch branches:</p>
<pre><code class="lang-typescript">git <span class="hljs-keyword">switch</span> other-branch
git <span class="hljs-keyword">switch</span> -  # Switch back to previous branch, similar to <span class="hljs-string">"cd -"</span>
git <span class="hljs-keyword">switch</span> remote-branch  # Directly <span class="hljs-keyword">switch</span> to remote branch and start tracking it
</code></pre>
<p>Well, that’s cool, but we’ve been switching branches in Git since forever using <code>git checkout</code>, why the need for a separate command? <code>git checkout</code> is a very versatile command - it can (among other things) check out or restore specific files or even specific commits, while the new <code>git switch</code> <em>only</em> switches the branch. Additionally, <code>switch</code> performs extra sanity checks that <code>checkout</code> doesn't, for example, switch would abort operation if it would lead to loss of local changes.</p>
<h3 id="heading-restore">Restore</h3>
<p>Another new subcommand/feature added in Git version 2.23 is <code>git restore</code>, that we can use to restore a file to the last committed version:</p>
<pre><code class="lang-typescript"># Unstage changes made to a file, same <span class="hljs-keyword">as</span> <span class="hljs-string">"git reset some-file.py"</span>
git restore --staged some-file.py

# Unstage and discard changes made to a file, same <span class="hljs-keyword">as</span> <span class="hljs-string">"git checkout some-file.py"</span>
git restore --staged --worktree some-file.py

# Revert a file to some previous commit, same <span class="hljs-keyword">as</span> <span class="hljs-string">"git reset commit -- some-file.py"</span>
git restore --source HEAD~<span class="hljs-number">2</span> some-file.py
</code></pre>
<p>The comments in the above snippet explain the workings of various <code>git restore</code>. Generally speaking <code>git restore</code> replaces and simplifies some of the use cases of <code>git reset</code> and <code>git checkout</code> which are already overloaded features. See also <a target="_blank" href="https://git-scm.com/docs/git#_reset_restore_and_revert">this docs section</a> for comparison of <code>revert</code>, <code>restore</code> and <code>reset</code>.</p>
<h3 id="heading-sparse-checkout">Sparse Checkout</h3>
<p>The next one is <code>git sparse-checkout</code>, a little more obscure feature that was added in Git 2.25, which was released on January 13, 2020.</p>
<p>Let’s say you have a large monorepo, with microservices separated into individual directories, and commands such as <code>checkout</code> or <code>status</code> are super slow because of the repository size, but maybe you really just need to work with a single subtree/directory. Well, <code>git sparse-checkout</code> to the rescue:</p>
<pre><code class="lang-typescript">$ git clone --no-checkout https:<span class="hljs-comment">//github.com/derrickstolee/sparse-checkout-example</span>
$ cd sparse-checkout-example
$ git sparse-checkout init --cone  # Configure git to only match files <span class="hljs-keyword">in</span> root directory
$ git checkout main  # Checkout only files <span class="hljs-keyword">in</span> root directory
$ ls
bootstrap.sh  LICENSE.md  README.md

$ git sparse-checkout set service/common

$ ls
bootstrap.sh  LICENSE.md  README.md  service

$ tree .
.
├── bootstrap.sh
├── LICENSE.md
├── README.md
└── service
    ├── common
    │   ├── app.js
    │   ├── Dockerfile
    ... ...
</code></pre>
<p>In the above example, we first clone the repo without actually checking out all the files. We then use <code>git sparse-checkout init --cone</code> to configure <code>git</code> to only match files in the root of the repository. So, after running checkout, we only have 3 files rather than the whole tree. To then download/checkout a particular directory, we use <code>git sparse-checkout set ...</code>.</p>
<p>As already mentioned, this can be very handy when working locally with huge repos, but it’s equally useful in CI/CD for improving the performance of a pipeline, when you only want to build/deploy part of the monorepo and there’s no need to check out everything.</p>
<p>For a detailed write-up about <code>sparse-checkout</code> see <a target="_blank" href="https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/">this article</a>.</p>
<h3 id="heading-worktree">Worktree</h3>
<h3 id="heading-git-worktree">Git Worktree</h3>
<ol>
<li><strong>What is a Git Worktree</strong></li>
</ol>
<p><a target="_blank" href="https://git-scm.com/docs/git-worktree">Git worktree</a> is a feature in Git. Before we see Git worktree, let us see the normal Git flow.</p>
<h4 id="heading-the-normal-git-flow"><strong>The normal Git flow</strong></h4>
<ul>
<li><p>You have one working folder.</p>
</li>
<li><p>You have one active branch.</p>
</li>
<li><p>Switching branches changes all files in that folder</p>
</li>
</ul>
<pre><code class="lang-javascript">my-app/
├── src/
├── README.md
└── .git/
</code></pre>
<p>When you run <code>git checkout “feature-abc”,</code> the whole folder switches to that branch.</p>
<h4 id="heading-the-git-work-tree-flow"><strong>The Git work tree flow</strong></h4>
<ul>
<li><p>Work trees let you have many working folders from the same repo.</p>
</li>
<li><p>Each folder can have its own branch.</p>
</li>
<li><p>You can work in all of them at the same time without switching anything.</p>
</li>
</ul>
<blockquote>
<p>In simple words, you can work in parallel without switching branches.</p>
</blockquote>
<pre><code class="lang-javascript">my-app/                    
├── src/
├── README.md
└── .git/

my-app-feature-a/          ← Worktree <span class="hljs-number">1</span> (feature-a branch)
├── src/
├── README.md
└── .git                   ← File points to main repo

my-app-feature-b/          ← Worktree <span class="hljs-number">2</span> (feature-b branch)
├── src/
├── README.md
└── .git                   ← File points to main repo
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764783507844/514d6633-0db8-437a-b470-6d21144715c8.webp" alt class="image--center mx-auto" /></p>
<ol start="2">
<li><strong>Git Worktree with Git Clone</strong></li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764783563711/4c37a2d9-84fe-43b4-bd6f-e2199be707db.webp" alt class="image--center mx-auto" /></p>
<p>The points above explain the concept. But the commands make it crystal clear.</p>
<p>This is what we do in a normal clone and what we do when we use work trees.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764783606520/afa68f61-f5f4-42fd-b53d-26ceaeaa76fe.webp" alt class="image--center mx-auto" /></p>
<ol start="3">
<li><strong>Git Worktree Commands</strong></li>
</ol>
<p>There are a few basic Git work tree commands you will use often.</p>
<p><strong>Create Worktree</strong></p>
<pre><code class="lang-javascript"># Create a work tree and a <span class="hljs-keyword">new</span> branch
git worktree add &lt;worktree-path&gt; -b &lt;<span class="hljs-keyword">new</span>-branch-name&gt;

# Example
git worktree add ../add-header -b feature/add-header


# Create a work tree <span class="hljs-keyword">from</span> an existing branch
git worktree add &lt;worktree-path&gt; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">branch-name</span>&gt;</span>

# Example
git worktree add ../ui-changes feature/ui-changes</span>
</code></pre>
<p><strong>List worktree</strong></p>
<pre><code class="lang-javascript"># list all active work trees
git worktree list
</code></pre>
<p><strong>Remove Worktree</strong></p>
<pre><code class="lang-javascript"># remove a work tree
git worktree remove &lt;worktree-path&gt;

# Example
git worktree remove ../add-header
</code></pre>
<p><strong>One Branch Per Worktree Rule</strong></p>
<p>Git has a simple rule for work trees. One branch can live in only one work tree at a time.</p>
<p>If the branch is already used in a work tree, Git will block you from using it again. See the screenshot below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764783901893/6c0669c0-eb5e-4c47-8d22-b64c0d517799.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-bisect">Bisect</h3>
<p>Last but not least, <code>git bisect</code>, which isn't so new (Git 1.7.14, released on May 13, 2012), but most people are using only <code>git</code> features from around 2005, so I think it's worth showing anyway.</p>
<p>As the <a target="_blank" href="https://git-scm.com/docs/git-bisect">docs page</a> describes it: <code>git-bisect</code> <em>- Use binary search to find the commit that introduced a bug</em>:</p>
<pre><code class="lang-typescript">git bisect start
git bisect bad HEAD  # Provide the broken commit
git bisect good <span class="hljs-number">479420</span>e  # Provide a commit, that you know works
# Bisecting: <span class="hljs-number">2</span> revisions left to test after <span class="hljs-built_in">this</span> (roughly <span class="hljs-number">1</span> step)
# [<span class="hljs-number">3258487215718444</span>a6148439fa8476e8e7bd49c8] Refactoring.

# Test the current commit...
git bisect bad  # If the commit doesn<span class="hljs-string">'t work
git bisect good # If the commit works

# Git bisects left or right half of range based on the last command
# Continue testing until you find the culprit

git bisect reset  # Reset to original commit</span>
</code></pre>
<p>We start by explicitly starting the bisection session with <code>git bisect start</code>, after which we provide the commit that doesn't work (most likely the <code>HEAD</code>) and the last known working commit or tag. With that information, <code>git</code> will check out a commit halfway between the <em>"bad"</em> and <em>"good"</em> commit. At which point we need to test whether that version has the bug or not, we then use <code>git bisect good</code> to tell <code>git</code> that it works or <code>git bisect bad</code> that it doesn't. We keep repeating the process until no commits are left and <code>git</code> will tell us which commit is the one that introduced the issue.</p>
<p>I recommend checking out the <a target="_blank" href="https://git-scm.com/docs/git-bisect">docs page</a> that shows a couple more options for git bisect, including visualizing, replaying, or skipping a commit.</p>
<h2 id="heading-cherry-picking-commits">Cherry-Picking Commits</h2>
<p>Need a specific commit from another branch? Cherry-picking lets you apply it to your current branch without merging the entire branch.</p>
<p><strong>How to use it:</strong></p>
<pre><code class="lang-typescript">git cherry-pick &lt;commit-hash&gt;
</code></pre>
<p><strong>Why it’s cool:</strong><br />It gives you the flexibility to bring in individual features or fixes without merging all the other changes from the source branch.</p>
<p><strong>Pro tip:</strong><br />This is especially useful when you need to backport bug fixes or small features.</p>
<h2 id="heading-blame-a-line-of-code">Blame a Line of Code</h2>
<p>Want to know who wrote a specific line of code? <code>git blame</code> gives you a line-by-line history of who changed what in a file.</p>
<p><strong>How to use it:</strong></p>
<pre><code class="lang-typescript">git blame &lt;filename&gt;
</code></pre>
<p><strong>Why it’s cool:</strong><br />It’s an easy way to track down who made a change and when, especially when debugging issues.</p>
<p><strong>Pro tip:</strong><br />Combine this with <code>git log -- &lt;file&gt;</code> to get a more detailed history of changes.</p>
<h2 id="heading-quick-commit-fix">Quick Commit Fix</h2>
<p>Forgot to add a file or made a typo in your commit message? <code>git commit --amend</code> lets you update the commit without creating a new one.</p>
<p><code>git commit --amend</code></p>
<p>You can fix mistakes instantly without cluttering your commit history.</p>
<p>This is great for squashing small mistakes without polluting your Git log with unnecessary commits.</p>
<h2 id="heading-tagging-a-commit">Tagging a Commit</h2>
<p>Tags are useful for marking specific points in your Git history, such as releases.</p>
<p><strong>How to use it:</strong></p>
<pre><code class="lang-typescript">git tag -a v1<span class="hljs-number">.0</span> -m <span class="hljs-string">"Version 1.0 release"</span>
</code></pre>
<p><strong>Why it’s cool:</strong><br />It helps in marking important milestones, making it easy to jump back to a particular version later.</p>
<p><strong>Pro tip:</strong><br />Use lightweight tags (<code>git tag &lt;tagname&gt;</code>When you don’t need additional metadata.</p>
<h2 id="heading-view-all-git-operations-git-reflog">View All Git Operations (Git Reflog)</h2>
<h3 id="heading-the-real-reason-developers-fear-git">The Real Reason Developers Fear Git</h3>
<p>Before we dive into the reflog, let’s address an uncomfortable truth:</p>
<p><strong>Most developers don’t trust themselves with Git.</strong></p>
<p>They’ve all lived through at least one horror story:</p>
<ul>
<li><p>A branch was accidentally deleted</p>
</li>
<li><p>A rebase gone wrong</p>
</li>
<li><p>A force push that wiped someone’s work</p>
</li>
<li><p>A commit lost in the void, never to be seen again</p>
</li>
</ul>
<p>So people stick to “safe” operations.<br />They avoid rebasing.<br />They avoid rewriting history.<br />They avoid anything that looks like it might ruin the repo.</p>
<p>But here’s the secret senior developers know:</p>
<p><strong>Git is far less delicate than you think — because the reflog remembers everything.</strong></p>
<h3 id="heading-wait-what-exactly-is-the-reflog">Wait… What Exactly Is the Reflog?</h3>
<p>You’ve probably used Git logs:</p>
<pre><code class="lang-javascript">git log
</code></pre>
<p>…but the log only shows reachable commits — the ones still connected to branches or tags.</p>
<p>The <strong>reflog (reference log)</strong> is different. It records <em>every movement</em> of branch heads, even if commits become “lost” or detached.</p>
<p>Every checkout.<br />Every reset.<br />Every branch switch.<br />Every rebase rewrite.<br />Every commit that disappears from the log.</p>
<p>Git keeps it all.</p>
<p>Run this:</p>
<pre><code class="lang-javascript">git reflog
</code></pre>
<p>And suddenly you see the <em>real</em> history of your repo — not just the final, polished timeline.</p>
<h3 id="heading-why-senior-engineers-rely-on-the-reflog-daily">Why Senior Engineers Rely on the Reflog Daily</h3>
<p>Senior developers love the reflog because it unlocks something powerful:</p>
<p><strong>1. It makes “dangerous” commands safe</strong></p>
<p>Want to rebase aggressively?<br />Want to rewrite history?<br />Want to force-push after cleaning up commits?</p>
<p>Seniors do all of this — because they know they can undo anything.</p>
<p><strong>2. It makes mistakes reversible</strong></p>
<p>Accidentally deleted a branch?</p>
<pre><code class="lang-javascript">git branch -D feature/payment
</code></pre>
<p>No panic.<br />The reflog has the commit:</p>
<pre><code class="lang-javascript">git reflog
git checkout -b feature/payment &lt;commit-id&gt;
</code></pre>
<p>Fixed.</p>
<p><strong>3. It saves work that you thought you lost forever</strong></p>
<p>Ever reset the wrong branch?</p>
<p>Ever commit something and forget where it went?</p>
<p>Ever stash something and later realize it didn’t apply cleanly?</p>
<p>Reflog keeps all of that.</p>
<p><strong>4. It speeds up debugging</strong></p>
<p>Seniors often ask:<br />“What commit was I on 20 minutes ago?”</p>
<p>Reflog answers that instantly.</p>
<p><strong>5. It encourages experimentation</strong></p>
<p>When you stop worrying about losing work, something amazing happens:</p>
<p>You explore.<br />You take risks.<br />You try new workflows.<br />You get <em>better</em> at Git.</p>
<h2 id="heading-squash-commits-1">Squash Commits</h2>
<p>Want to clean up your commit history before pushing? Squashing commits lets you combine several into one for a neater history.</p>
<p><strong>How to use it:</strong></p>
<pre><code class="lang-typescript">git rebase -i HEAD~&lt;<span class="hljs-built_in">number</span>-<span class="hljs-keyword">of</span>-commits&gt;
</code></pre>
<p><strong>Why it’s cool:</strong><br />Squashing makes your commit history look polished and professional, especially when you’re sharing with a team.</p>
<p><strong>Pro tip:</strong><br />This is ideal for combining multiple small fixes into one clear commit before pushing.</p>
<h1 id="heading-git-best-practices">Git Best Practices</h1>
<p>The use of the Git tool is crucial for the development process of an application, whether working in a team or individually. However, it’s common to encounter messy repositories, commits with unclear messages that don’t convey useful information, and misuse of branches, among other issues. Knowing how to use Git correctly and following good practices is essential for those who want to excel in the job market.</p>
<h2 id="heading-stop-breaking-your-codebase-the-git-hooks-nobody-told-you-about">Stop Breaking Your Codebase: The Git Hooks Nobody Told You About</h2>
<p>Automated tests, block secrets, and enforce lean commits before disaster strikes.</p>
<p>When I first discovered Git Hooks, I felt like I had unlocked a hidden superpower in Git. Imagine automating small and repetitive tasks — without needing extra external tools or fancy CI/CD pipelines, right inside your local Git workflow. That’s exactly what Git Hooks let you do.</p>
<h3 id="heading-what-are-git-hooks">What Are Git Hooks?</h3>
<p>Git Hooks are scripts that Git automatically executes before or after certain events, like committing, pushing, or merging code.</p>
<p>Think of them as a little “guardians“ of your repository. For example:</p>
<ul>
<li><p>A pre-commit hook can check your code formatting before a commit is made.</p>
</li>
<li><p>A pre-push hook can run tests before code is pushed to the remote.</p>
</li>
<li><p>A commit-msg hook can enforce commit conventions</p>
</li>
</ul>
<p>Git already provides sample hooks in every repository inside the <code>.git/hooks/</code> folder. You just need to enable or customize them.</p>
<h3 id="heading-why-githooks-matter-in-the-real-world">Why GitHooks Matter in The Real World?</h3>
<p>In theory, you could ask your team to remember rules like:</p>
<ul>
<li><p>“Always format your code before committing.”</p>
</li>
<li><p>“Don’t push without running tests.”</p>
</li>
<li><p>“Follow our commit message convention.”</p>
</li>
</ul>
<p>But in reality, people forget. Deadline creep in, and rules get broken.</p>
<p>Hooks automate these rules, ensuring consistency and saving you from painful mistakes.</p>
<h3 id="heading-real-world-scenarios-amp-examples">Real-World Scenarios &amp; Examples</h3>
<p><strong>1. Keeping Code Clean Before Commit</strong></p>
<p>Imagine you’re working on a Python project. The team agreed to use <code>black</code> for formatting, but developers sometimes forget.</p>
<p><strong>Solution:</strong> Add a <code>pre-commit</code> hook that auto-formats code before every commit.</p>
<pre><code class="lang-typescript"># .git/hooks/pre-commit
#!<span class="hljs-regexp">/bin/</span>sh
echo <span class="hljs-string">"Running Black formatter..."</span>
black .
git add .
</code></pre>
<p>✅ Result: Every commit is properly formatted — no arguments needed in code reviews.</p>
<p><strong>2. Enforcing Commit Message Convention</strong></p>
<p>Let’s say your team uses Conventional Commits. You want commit messages like:</p>
<pre><code class="lang-typescript">feat: add login API
fix: handle <span class="hljs-literal">null</span> pointer exception
docs: update README
</code></pre>
<p><strong>Solution:</strong> Use a <code>commit-msg</code> hook to reject invalid commit messages.</p>
<pre><code class="lang-typescript"># .git/hooks/commit-msg
#!<span class="hljs-regexp">/bin/</span>sh
commit_msg_file=$<span class="hljs-number">1</span>
commit_msg=$(cat <span class="hljs-string">"$commit_msg_file"</span>)
pattern=<span class="hljs-string">"^(feat|fix|docs|style|refactor|test|chore):"</span>
<span class="hljs-keyword">if</span> ! echo <span class="hljs-string">"$commit_msg"</span> | grep -qE <span class="hljs-string">"$pattern"</span>; then
  echo <span class="hljs-string">"❌ Commit message invalid! Must follow Conventional Commits."</span>
  exit <span class="hljs-number">1</span>
fi
</code></pre>
<p>✅ Result: Developers can’t commit unless they follow the convention.</p>
<p><strong>3. Running Tests Before Pushing</strong></p>
<p>Ever pushed broken code that failed the CI pipeline? Painful.</p>
<p><strong>Solution:</strong> Add a <code>pre-push</code> hook that runs tests locally before pushing.</p>
<pre><code class="lang-typescript"># .git/hooks/pre-push
#!<span class="hljs-regexp">/bin/</span>sh
echo <span class="hljs-string">"Running tests before push..."</span>
npm test
<span class="hljs-keyword">if</span> [ $? -ne <span class="hljs-number">0</span> ]; then
  echo <span class="hljs-string">"❌ Tests failed! Push aborted."</span>
  exit <span class="hljs-number">1</span>
fi
</code></pre>
<p>✅ Result: Only the tested code reaches the remote repository.</p>
<p><strong>4. Blocking Secrets from Being Committed</strong></p>
<p>A classic mistake: pushing an API key or password to GitHub.</p>
<p><strong>Solution:</strong> Add a <code>pre-commit</code> hook that scans for secrets.</p>
<pre><code class="lang-typescript"># .git/hooks/pre-commit
#!<span class="hljs-regexp">/bin/</span>sh
<span class="hljs-keyword">if</span> git diff --cached | grep -q <span class="hljs-string">"API_KEY"</span>; then
  echo <span class="hljs-string">"❌ Secret detected! Commit aborted."</span>
  exit <span class="hljs-number">1</span>
fi
</code></pre>
<p>✅ Result: Accidental leaks are caught before they leave your machine.</p>
<p><strong>Sharing Hooks with Your Team</strong></p>
<p>By default, hooks live in <code>.git/hooks/</code> and aren’t version-controlled. To share them with your team:</p>
<ol>
<li><p>Create a folder, e.g. <code>.githooks/</code></p>
</li>
<li><p>Store all hooks there</p>
</li>
<li><p>Set Git to use that directory:</p>
</li>
</ol>
<pre><code class="lang-typescript">git config core.hooksPath .githooks
</code></pre>
<p>Now, everyone using the repo gets the same hooks.</p>
<h3 id="heading-pro-tip-use-tools-to-manage-hooks">Pro Tip: Use Tools to Manage Hooks</h3>
<p>Instead of writing raw shell scripts, you can use tools like:</p>
<ul>
<li><p>Husky (for JavaScript projects)</p>
</li>
<li><p>pre-commit (multi-language support)</p>
</li>
</ul>
<p>These make it easier to manage and share hooks across projects. I am regularly using pre-commit tools on every public repository to ensure no .env files are mistakenly pushed, no secrets are shared, code is well formatted, etc. Here is a simplified pre-commit config from one of my repository <a target="_blank" href="https://github.com/imShakil/pacli"><strong>pacl</strong>i(personal access CLI tool**)**</a><strong>.</strong></p>
<pre><code class="lang-typescript">repos:
  - repo: https:<span class="hljs-comment">//github.com/psf/black</span>
    rev: <span class="hljs-number">25.1</span><span class="hljs-number">.0</span>
    hooks:
      - id: black
        args: [<span class="hljs-string">"--line-length=120"</span>]

  - repo: https:<span class="hljs-comment">//github.com/pycqa/flake8</span>
    rev: <span class="hljs-number">7.3</span><span class="hljs-number">.0</span>
    hooks:
      - id: flake8
        args: [<span class="hljs-string">"--max-line-length=120"</span>]

  - repo: https:<span class="hljs-comment">//github.com/pre-commit/pre-commit-hooks</span>
    rev: v6<span class="hljs-number">.0</span><span class="hljs-number">.0</span>
    hooks:
      - id: trailing-whitespace
      - id: end-<span class="hljs-keyword">of</span>-file-fixer
      - id: check-yaml

  - repo: https:<span class="hljs-comment">//github.com/pre-commit/mirrors-mypy</span>
    rev: v1<span class="hljs-number">.17</span><span class="hljs-number">.1</span>
    hooks:
      - id: mypy

  - repo: https:<span class="hljs-comment">//github.com/PyCQA/bandit</span>
    rev: <span class="hljs-number">1.8</span><span class="hljs-number">.6</span>
    hooks:
      - id: bandit
</code></pre>
<h2 id="heading-perfect-git-commit-messages">Perfect Git Commit Messages</h2>
<p>Commit serves as the tangible building blocks of a programmer’s craft. They act as the icing on the cake of code, and when written correctly, they bring substantial value. A well-written commit message becomes indispensable because it provides context; otherwise, a commit message wouldn’t be needed in the first place.</p>
<p><mark>A good commit shows whether a developer is a good collaborator.</mark></p>
<p>A common mistake among developers is treating the Git repository is a backup system. Randomly committing to capture the current state of code can impede your ability to comprehend past changes when checking out the codebase in the future. Commit messages like “WIP”, “Off for lunch”, “End of code for today”, “I am tired AF”, “Happy Weekend Team”, and “First to commit” will only clutter your Git log, making it too difficult to understand the essential commits you have made because none of these messages consists of any additional value.</p>
<h3 id="heading-8-standard-rules-for-writing-a-perfect-commit-message">8 Standard Rules for Writing a Perfect Commit Message</h3>
<p>These rules provide guidelines and best practices that ensure your commit messages are properly formatted and convey clear information. While the specific rules may vary based on different resources, the general aim is to enhance the readability and understandability of the commit message within the Git version control system.</p>
<ol>
<li><strong>Limit Subject to 50 Characters (Max)</strong></li>
</ol>
<p>When crafting the subject line of a commit message, it’s advisable to keep it concise and focused. The subject line serves as a quick summary of the commit’s purpose and should ideally be limited to a maximum of 50 characters.</p>
<p><mark>Struggling to fit within the 50-character limit can be indicative of a lack of clarity about the commit’s intent</mark>. Commit messages should be concise, clear, and easy to understand on their own. By adhering to this character limit, you are forced to prioritize the most critical information, making it easier for your team and your future self to understand the nature of the change at a glance.</p>
<ol start="2">
<li><strong>Capitalize only the first letter of the subject line</strong></li>
</ol>
<p>When composing a commit message, employ title case by capitalizing the first letter of the subject line, just like writing a concise sentence. Leave the rest of the message, including any additional details, in lowercase.</p>
<ol start="3">
<li><strong>Don’t put a period at the end of the subject line</strong></li>
</ol>
<p>The reason for not ending the subject line with a period is partly historical and partly to maintain a consistent style. The convention is to treat the subject line as the title or the command, which is why it’s written in the imperative mood (e.g., “Add feature” or “Fix bug” rather than “Added feature” or “Fixed bug”). Omitting the period at the end helps reinforce this convention and keeps subject lines concise.</p>
<p><code>git commit -v -m "Create the Cart Feature with a Nice Animation"</code></p>
<ol start="4">
<li><strong>Put a blank line between the Subject line and the body</strong></li>
</ol>
<p>While this guideline might appear unusual, it’s rooted in practicality. Many developers employ command-line interfaces for Git, which often lack automatic word wrapping. Consequently, intentional formatting rules have been introduced to ensure consistent and legible commit messages.</p>
<pre><code class="lang-typescript">git commit -v -m <span class="hljs-string">"Create the Cart Feature with a Nice Animation

Body...
"</span>
</code></pre>
<ol start="5">
<li><strong>Wrap Lines at 72 Characters for the Commit Body</strong></li>
</ol>
<p>It’s important to clarify that adhering to this guideline isn’t about traditional word wrapping, instead, this practice arises in the consideration that command-line users might experience truncated commit bodies beyond 72 characters.</p>
<p><code>Most of the time, your message will exceed 72 characters in length</code>. In such cases, it’s advisable to break the text and continue your sentence on the next line, as demonstrated in the commit message below:</p>
<pre><code class="lang-typescript">git commit -v -m <span class="hljs-string">"Create the Cart Feature with a Nice Animation

Enhanced the CSS layout of the cart section, addressing text
alignment issues and refining the layout for improved aesthetics
and readability."</span>
</code></pre>
<p>In conclusion, a standard practice for denoting bullet points involves using a hyphen or asterisk, followed by a single space. Additionally, it’s important to maintain a hanging indent to enhance organizational clarity.</p>
<ol start="6">
<li><strong>Use the imperative mood</strong></li>
</ol>
<p>A valuable practice involves crafting commit messages with the underlying understanding that the commit, when implemented, will achieve a precise action. Construct your commit message in a manner that logically completes the sentence <em>“If applied, this commit will…”.</em> For instance, rather than,<code>git commit -m "Fixed the bug on the layout page"</code> ❌, use this <code>git commit -m "Fix the bug on the layout page"</code> ✔</p>
<ol start="7">
<li><strong>Explain “What“ and “Why“, but not “How“</strong></li>
</ol>
<p><mark>Limiting commit messages to “what“ and “why“ creates concise yet informative explanations of each change. Developers seeking to understand how the code was implemented can refer directly to the codebase. Instead, highlight what was altered and the rationale for the change, including what component or area was affected</mark></p>
<ol start="8">
<li><strong>Angular’s Commit Message Practices</strong></li>
</ol>
<p>Angular stands as a prominent illustration of effective commit messaging practices. The Angular team advocates for the use of specific prefixes when crafting commit messages. These prefixes include “chore: ,” “docs: ,” “style: ,” “feat: ,” “fix: ,” “refactor: ,” and “test: .”. By incorporating these prefixes, the commit history becomes a valuable resource for understanding the nature of each commit.</p>
<h2 id="heading-naming-conventions-for-git-branches">Naming Conventions for Git Branches</h2>
<p>When you are working with code versioning, one of the main good practices that we should follow is using clear, descriptive names for branches, commits, and pull requests. Ensuring a concise workflow for all team members is essential. In addition to gaining productivity, documenting the development process of the project historically simplifies teamwork. By following these best practices, you will see benefits soon.</p>
<p>Based on it, the community created a branch naming convention that you can follow in your project. The use of the following items below is optional, but they can help to improve your development skills.</p>
<p><strong>1. Lowercase:</strong> Don't use uppercase letters in the branch name, stick to lowercase.</p>
<p><strong>2. Hyphen separated:</strong> If your branch name consists of more than one word, separate them with a hyphen. following the kebab-case convention. Avoid PascalCase, camelCase, or snake_case;</p>
<p><strong>3. (a-z, 0-9):</strong> Use only alphanumeric characters and hyphens in your branch name. Avoid any non-alphanumeric character;</p>
<p><strong>4. Please, don't use continuous hyphens (--).</strong> This practice can be confusing. For example, if you have branch types (such as a feature, bugfix, hotfix, etc.), use a slash (/) instead;</p>
<p><strong>5. Avoid ending your branch name with a hyphen</strong>. It does not make sense because a hyphen separates words, and there's no word to separate at the end.</p>
<p><strong>6. This practice is the most important:</strong> Use descriptive, concise, and clear names that explain what was done on the branch.</p>
<p><strong>Wrong branch names</strong></p>
<ul>
<li><p><code>fixSidebar</code></p>
</li>
<li><p><code>feature-new-sidebar-</code></p>
</li>
<li><p><code>FeatureNewSidebar</code></p>
</li>
<li><p><code>feat_add_sidebar</code></p>
</li>
</ul>
<p><strong>Good branch names</strong></p>
<ul>
<li><p>feature/new-sidebar</p>
</li>
<li><p>add-new-sidebar</p>
</li>
<li><p>hotfix/interval-query-param-on-get-historical-data</p>
</li>
</ul>
<h2 id="heading-always-git-pull-before-working-on-a-new-feature">Always git pull before working on a new feature</h2>
<p>Do this to avoid merge conflicts as much as possible.</p>
<p>Merge conflicts happen when:</p>
<ul>
<li><p>2 people are working on the same code in the same file</p>
</li>
<li><p>1 person pushes their code first</p>
</li>
<li><p>When the 2nd person tries to push their code, it conflicts with the code from the first person</p>
</li>
<li><p>In this case, git doesn’t know how to resolve this conflict in changes, and doesn’t want to for fear of causing either one developer to lose progress</p>
</li>
<li><p>As such, git causes a merge conflict — essentially asking the developers to handle the conflicting code themselves</p>
</li>
</ul>
<p>Advantages of running “git pull“ before working on a new feature:</p>
<ul>
<li><p>There might still be merge conflicts, but they are likely to contain smaller changes and be more manageable.</p>
</li>
<li><p>You ensure that your local codebase is up to date when you start working on something.</p>
</li>
</ul>
<h2 id="heading-remember-to-delete-branches-after-you-merge-them">Remember to delete branches after you merge them</h2>
<p>In a large project, chances are that devs are expected to create a new branch to work on a new feature. Which is good practice, as this acts as an additional layer of defence against devs accidently screwing up the master branch.</p>
<p><mark>But when you forget to delete their branches after merging, these branches pipe up more and more.</mark></p>
<p>Note — git stores your branches locally in the directory .git/refs/heads</p>
<p>So, what happens when we forget to delete 1000 branches? Git now has 1000 additional unused folders inside .git/refs/heads, which clogs things up and slows things down.</p>
<p>Verdict — remember to delete your branches after you merge them successfully</p>
<h2 id="heading-git-pruning-how-to-keep-your-repository-git-clean-and-efficient">Git Pruning: How to Keep Your Repository (.git) Clean and Efficient?</h2>
<p>As your project grows, your git repository can get cluttered with old, unreachable objects (commits, branches, trees) that no longer serve any purpose. If left unchecked, this clutter can slow things down, take up unnecessary disk space, and make the repo harder to manage.</p>
<p>Recently, in one of the projects I was working on, a <strong>2+ year-old codebase</strong> with contributions from many developers, I noticed something strange. Whenever I did a <strong>git fetch</strong> or <strong>git pull</strong>, it felt unusually slow. I deep dived into it and realized even after working on the project for just 3 months, my local repo was still holding onto stale branches and commits that were no longer relevant. These were <strong>taking up space and could lead to unnecessary conflict</strong>s or overhead later.</p>
<p>So, I started researching, and one of the simplest solutions I found was <strong>Git Pruning</strong>: <em>a clean and easy way to keep your repository tidy and efficient.</em></p>
<h3 id="heading-what-are-git-objects">What are Git Objects?</h3>
<p>Git stores everything, including commits, trees, and blobs, in the <strong><em>.git</em></strong>/objects folder. These objects are 3 types:</p>
<ul>
<li><p><strong>Commits</strong>: Representing snapshots of your project at different points in time.</p>
</li>
<li><p><strong>Trees</strong>: Representing directories and their structure.</p>
</li>
<li><p><strong>Blobs</strong>: Representing individual files.</p>
</li>
</ul>
<p>Over time, as you <strong>create, modify, and delete</strong> files and commits, Git’s internal database can accumulate objects that are no longer referenced by any branch or tag. They’re like files in your Downloads folder that you forgot about, just sitting there taking up space. These objects become <strong>“unreachable”</strong> and can consume unnecessary disk space.</p>
<p>Example :</p>
<ul>
<li><p>Delete branches,</p>
</li>
<li><p>Force-push changes,</p>
</li>
<li><p>Rewrite history with commands like git rebase.</p>
</li>
</ul>
<h3 id="heading-what-is-git-pruning">What is Git Pruning?</h3>
<p><strong>Git pruning is the cleanup process.</strong> It removes these unused objects and keeps your repository clean.</p>
<h3 id="heading-how-does-it-work">How does it work?</h3>
<p>Pruning is part of <a target="_blank" href="https://www.geeksforgeeks.org/git/git-gc-garbage-collection/"><strong><em>Git’s garbage collection</em></strong></a> (git gc). By default, Git waits 7 days before removing unreachable objects, in case you want to recover them. But you can prune right away using:</p>
<pre><code class="lang-xml">git gc --prune=now
</code></pre>
<ul>
<li><p><strong>Basic pruning</strong>: Deletes unreachable objects older than 7 days<a target="_blank" href="https://www.geeksforgeeks.org/git/git-gc-garbage-collection/">.</a></p>
</li>
<li><p><strong>Aggressive pruning</strong>: Deletes even more, including some objects still in the reflog.</p>
</li>
</ul>
<p>👉 <strong>Reflog? It</strong> is a git log that tracks all reference updates (like branch changes, HEAD movements) in your local repository. This means whenever you switch branches, reset a commit, or change the HEAD, Git records it in the reflog. It allows you to go back to previous states even if those commits are no longer visible in the current branch history. In simple words, reflog is like an "undo history" in Git; it gives you a way to go back in time.</p>
<h3 id="heading-why-and-when-to-use-pruning">Why and When to Use Pruning?</h3>
<p>Let’s say you’re working on a feature branch called feature/signup.</p>
<ol>
<li><p>You commit 10 changes while experimenting.</p>
</li>
<li><p>Later, you realize the history is messy, so you squash your commits and <strong>force push</strong> the branch.</p>
</li>
<li><p>From your perspective, everything looks fine. You only see the clean squashed commit on GitHub.</p>
</li>
</ol>
<p>But behind the scenes, your local <strong>.git/objects</strong> folder still contains those 10 old commits. They are unreachable, with no branch points to them, but they’re still taking up space.</p>
<p>Now imagine your teammate clones the repository or fetches/pulls the PR. The repo feels heavier than it should. <strong>Fetches take longer. Disk usage keeps growing.</strong></p>
<p>This is when pruning helps:</p>
<pre><code class="lang-xml">git gc --prune=now // Prune all objects now

git gc --prune="2025-01-01" //Prune objects older than a specific date

git gc --aggressive --prune=now // For a deeper clean: Aggressive Pruning

⚠️ Alert : It can delete objects you might still need.
</code></pre>
<p>After running it, Git clears out those unreachable commits. The <strong>.git/objects</strong> folder shrinks. Your repository is faster to clone, lighter to push around, and free of stale history.</p>
<p><strong><em>Before : (You can see how many files are in .git/objects)</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763633377316/51df3499-75d7-47a8-af20-eaa584607c53.png" alt class="image--center mx-auto" /></p>
<p><strong><em>Now: Let's run git pruning and clean unreachable objects</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763633404238/2a7e7a54-bca1-4f64-9faf-3f0c2dbf4b82.png" alt class="image--center mx-auto" /></p>
<p><strong><em>After: Just look at the difference, how much useless reference it cleared</em></strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763633421985/10405909-4f2f-491e-bcf5-69f8c0df0f5b.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-final-thoughts-amp-questions">Final Thoughts &amp; Questions</h3>
<p><strong>1. Is git prune safe to use?</strong></p>
<p>Yes, git prune only removes truly unreachable objects. It won’t delete anything referenced by branches or tags.</p>
<p><strong>2. When should I run git prune?</strong></p>
<ul>
<li><p>Force-push and leave behind old commits,</p>
</li>
<li><p>Performing rebases on a repository is cluttered</p>
</li>
<li><p>Delete branches and want to clear their leftovers,</p>
</li>
<li><p>Notice your repo is bigger than it should be.</p>
</li>
<li><p>Repo fetching and pulling take longer than expected</p>
</li>
<li><p>When your project is going through development for a long time</p>
</li>
</ul>
<p><strong>3. What’s the difference between local and remote pruning?</strong></p>
<ul>
<li><p>Local pruning removes unreachable objects in your local repository.</p>
</li>
<li><p>Remote pruning removes references from deleted remote branches.</p>
</li>
</ul>
<p><strong>4. What are the commands to remember?</strong></p>
<ul>
<li><p>git gc --prune=now → Clean local repo immediately.</p>
</li>
<li><p>git fetch --prune origin → Remove stale remote branches.</p>
</li>
<li><p>git prune --dry-run → Preview before deleting.</p>
</li>
</ul>
<h2 id="heading-best-git-guis-compared">Best Git GUIs Compared</h2>
<p>Git is a version control system (VCS) that allows you to track the development of a project over time. At the time of Git’s inception in 2005, developers had to use the command line interface (CLI) to manage Git. Learning and using a command line is often extremely difficult task for many developers and in some cases represents a significant barrier of entry for those seeking to leverage the power of Git.</p>
<p>Enter the graphical user interface (GUI), also referred to as a Git Client. A <a target="_blank" href="https://www.gitkraken.com/git-client">Git GUI</a> is a tool that helps developers visualize their Git repositories and run Git actions with a few simple mouse clicks or keyboard shortcuts.</p>
<p>It’s common for new and seasoned developers to leverage Git UI in their regular workflow. As you learn more about Git and interact in related communities, you will likely notice that some people have very strong opinions about using a GUI vs the CLI. Both tools have significant benefits, and it’s important to remember that you should select the tools that help you write code you are proud of. Millions of developers around the world use Git GUIs to make their lives easier and level up their coding.</p>
<p>Check out <a target="_blank" href="https://www.gitkraken.com/blog/best-git-gui-client">this article</a> to figure out which is the best Git GUI.</p>
<h1 id="heading-git-tips">Git Tips</h1>
<p><a target="_blank" href="https://github.com/git-tips/tips">https://github.com/git-tips/tips</a></p>
<h2 id="heading-git-merge-vs-git-rebase">Git Merge vs Git Rebase</h2>
<p>When navigating the Git universe for version control, grasping the art of choosing between <code>git merge</code> and <code>git rebase</code> is pivotal for streamlining and organizing code management. Both wield considerable merging prowess, yet appropriateness and impact shimmer in distinct scenarios.</p>
<h3 id="heading-git-merge">Git Merge</h3>
<p><code>git-merge</code> is a non-destructive operation designed to weave changes from two branches into a harmonious tapestry. It forges a connection between the histories of these branches by crafting a brand new “merge commit“.</p>
<p><strong>Advantages</strong></p>
<ul>
<li><p>Preserve Historical Integrity: The merge operation reverently preserves the authentic history of both branches, leaving no tale untold.</p>
</li>
<li><p>Simple and Intuitive Merge: This approach is a friendly gateway for Git novices, offering simplicity and clarity in its operation.</p>
</li>
</ul>
<p><strong>Scenarios To Be Used</strong></p>
<p>git merge shines brightest in team collaborations, where safeguarding a comprehensive history and delineating clear merge points is deemed invaluable.</p>
<h3 id="heading-git-rebase">Git Rebase</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=yTFC_MvwJvQ">https://www.youtube.com/watch?v=yTFC_MvwJvQ</a></div>
<p> </p>
<p><code>git rebase</code>performs a graceful dance, placing changes from one branch atop the freshest alterations on another. This intricate process often involves a rhythmic rewriting of the commit history, sculpting it into a more linear narrative.</p>
<p><strong>Advantages</strong></p>
<ul>
<li><p>Clean Linear History 📜: Rebase choreographs a symphony of commits, resulting in a pristine and linear project history.</p>
</li>
<li><p>Avoid Redundant Merge Commits🚫🔄: It’s the maestro of minimizing unnecessary merge commits, keeping the melody of your project smooth.</p>
</li>
</ul>
<p><strong>Scenarios to be Used</strong></p>
<p><code>rebase</code> is the virtuoso when it comes to refining commits on a personal branch or updating a feature branch before unveiling changes to the entire team.</p>
<h3 id="heading-the-golden-rule-of-git-re-basing">The Golden Rule of Git Re-basing</h3>
<p>👑 <mark>“Never use </mark> <code>git rebase</code> <mark>on public branches.” This royal decree stands firm to prevent historical dissonance among team members, averting the cacophony of confusion that may arise from altered histories.</mark></p>
<h3 id="heading-choosing-between-git-merge-and-git-rebase">Choosing Between Git Merge and Git Rebase</h3>
<p>When faced with the decision of <code>git merge</code> versus <code>git rebase</code>, thought consideration of your work environment and the team’s workflow is key:</p>
<ul>
<li><p>For private or nascent feature branches, opting for <code>git rebase</code> can be akin to tidying up the stage before a grand performance. It helps maintain a clear and uncluttered history, especially when preparing for a pull request.</p>
</li>
<li><p>On the public branch in team collaborations, embracing <code>git merge</code> is like choosing the steady path. It’s a safer change, retaining a comprehensive historical record that’s effortlessly comprehensible and traceable for all team members.</p>
</li>
</ul>
<p><a target="_blank" href="https://www.atlassian.com/git/tutorials/merging-vs-rebasing">https://www.atlassian.com/git/tutorials/merging-vs-rebasing</a></p>
<h2 id="heading-undoing-commits-amp-changes">Undoing Commits &amp; Changes</h2>
<h3 id="heading-git-revert-checkout-and-reset">Git Revert, Checkout, and Reset</h3>
<p>These three commands have entirely different purposes. They are not remotely similar.</p>
<p><strong>git revert</strong></p>
<p>This command creates a new commit that undoes the changes from a previous commit. This command adds a new history to the project (it doesn’t modify the existing history).</p>
<p><strong>git checkout</strong></p>
<p>This command checks out content from the repository and puts it in your worktree. It can also have other effects, depending on how the command was invoked. For instance, it can also change which branch you are currently working on. This command doesn’t make any changes to the history.</p>
<p><strong>git reset</strong></p>
<p>This command is a little more complicated. It actually does a couple of different things depending on how it is invoked. It modifies the index (the so-called "staging area"). Or it changes which commit a branch head is currently pointing at. This command may alter existing history (by changing the commit that a branch references).</p>
<h3 id="heading-using-these-commands">Using these commands</h3>
<p>If a commit has been made somewhere in the project’s history, and you later decide that the commit is wrong and should not have been done, then git revert is the tool for the job. It will undo the changes introduced in the bad commit, recording the “undo“ in the history.</p>
<p>If you have modified a file in your working tree, but haven't committed the change, then you can use <code>git checkout</code> to check out a fresh-from-repository copy of the file.</p>
<p>If you have made a commit, but haven't shared it with anyone else, and you decide you don't want it, then you can use <code>git reset</code> to rewrite the history so that it looks as though you never made that commit.</p>
<p>These are just some of the possible usage scenarios. There are other commands that can be useful in some situations, and the above three commands have other uses as well.</p>
<h2 id="heading-the-difference-between-git-pull-and-git-fetch">The difference between <code>git pull</code> and <code>git fetch</code></h2>
<p>In the simplest terms, <code>git pull</code> does a <code>git fetch</code> followed by a <code>git merge</code>.</p>
<p><code>git fetch</code> updates your remote-tracking branches under <code>refs/remotes/&lt;remote&gt;/</code>. This operation is safe to run at any time since it never changes any of your local branches under <code>refs/heads</code>.</p>
<p><code>git pull</code> brings a local branch up-to-date with its remote version, while also updating your other remote-tracking branches.</p>
<p>From the Git documentation for git pull:</p>
<blockquote>
<p><code>git pull</code> runs <code>git fetch</code> with the given parameters and then depending on configuration options or command line flags, will call either <code>git rebase</code> or <code>git merge</code> to reconcile diverging branches.</p>
</blockquote>
<h2 id="heading-the-difference-between-head-and-head-in-git">The difference between HEAD^ and HEAD~ in Git</h2>
<ul>
<li><p><code>&lt;rev&gt;~&lt;n&gt;</code> goes backward <em>n</em> parents from <em>rev</em>, selecting the first parent each time.</p>
</li>
<li><p>Use <code>&lt;rev&gt;^&lt;n&gt;</code> to select the <em>n</em>-th immediate parent of the merge commit <em>rev</em>.</p>
</li>
<li><p>Use <code>~</code> most of the time, to go back a number of generations and always choose the first parent of merge commits, commonly what you want.</p>
</li>
<li><p>Use <code>^</code> on merge commits — because they have two or more <em>immediate</em> parents.</p>
</li>
<li><p>In my experience, selecting a particular immediate parent of a merge commit by its index order, <em>e.g.</em>, <code>B^3</code>, is rare. It’s also error-prone. Just use a hash when you can.</p>
</li>
<li><p>NOTE: <code>HEAD~3</code> is equivalent to <code>HEAD~~~</code> and <code>HEAD~1~1~1</code> — but <code>HEAD^2</code> is <strong>not</strong> equivalent to <code>HEAD^^</code>.</p>
</li>
</ul>
<p>Mnemonics:</p>
<ul>
<li><p>Tilde <code>~</code> is almost linear in appearance and wants to go backward in a straight line.</p>
</li>
<li><p>Caret <code>^</code> suggests a merge commit: an interesting segment of a tree or a fork in the road.</p>
</li>
</ul>
<h2 id="heading-git-push-origin-head">git push origin HEAD</h2>
<p>We can use <em>“git push origin HEAD”</em> over <em>“git push origin longass_branch_name”</em></p>
<p>When we work on a feature, we usually work on a branch. This way, if we accidentally screw up, we screw up only our branch, and not the master branch.</p>
<p>Branch names can get pretty long in larger projects. For instance:</p>
<ul>
<li>JIRAPROJECT18001_refactor_this_certain_feature_for_reasons</li>
</ul>
<p>To push our changes to this branch, we can simply do:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*G8a6cLIOg-d79hnS.png" alt /></p>
<p>Instead of:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*eE6IMXcSEJjSESzM.png" alt /></p>
<p>This is just a pain to type out</p>
<h2 id="heading-see-a-graph-of-your-branches">See a Graph of Your Branches</h2>
<p>This command gives you a visual overview of your branch history, making it easier to see merges, branches, and commits.</p>
<p><strong>How to use it:</strong></p>
<pre><code class="lang-typescript">git log --graph --oneline --all
</code></pre>
<p><strong>Why it’s cool:</strong><br />It’s an at-a-glance view of your project’s structure, especially helpful for understanding complex branch setups.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In conclusion, by integrating these modern command-line tools and applying best practices of Git into your workflow, you can enhance your productivity and focus on crafting software that creates real business value.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://levelup.gitconnected.com/git-and-workflow-with-gitflow-5f9f76530835">https://levelup.gitconnected.com/git-and-workflow-with-gitflow-5f9f76530835</a></p>
<p><a target="_blank" href="https://medium.com/@Adem_Korkmaz/git-flow-a-detailed-overview-24e0dfa28f7a">https://medium.com/@Adem_Korkmaz/git-flow-a-detailed-overview-24e0dfa28f7a</a></p>
<p><a target="_blank" href="https://medium.com/thecapital/understanding-git-workflows-and-why-git-flow-is-the-best-0e5f4c4f36c3">https://medium.com/thecapital/understanding-git-workflows-and-why-git-flow-is-the-best-0e5f4c4f36c3</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/good-commit-vs-your-commit-how-to-write-a-perfect-git-commit-message-6e96ab6357fa">https://levelup.gitconnected.com/good-commit-vs-your-commit-how-to-write-a-perfect-git-commit-message-6e96ab6357fa</a></p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/how-to-write-better-git-commit-messages/">https://www.freecodecamp.org/news/how-to-write-better-git-commit-messages/</a></p>
<p><a target="_blank" href="https://dev.to/basementdevs/be-a-better-developer-with-these-git-good-practices-2dim">https://dev.to/basementdevs/be-a-better-developer-with-these-git-good-practices-2dim</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/top-30-git-commands-you-should-know-to-master-git-cli-f04e041779bc">https://levelup.gitconnected.com/top-30-git-commands-you-should-know-to-master-git-cli-f04e041779bc</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/14-git-things-i-regret-not-knowing-earlier-20956c192b2b">https://levelup.gitconnected.com/14-git-things-i-regret-not-knowing-earlier-20956c192b2b</a></p>
<p><a target="_blank" href="https://blog.stackademic.com/20-git-command-line-tricks-every-developer-should-know-bf817e83d6b9">https://blog.stackademic.com/20-git-command-line-tricks-every-developer-should-know-bf817e83d6b9</a></p>
<p><a target="_blank" href="https://medium.com/@jake.page91/the-guide-to-git-i-never-had-a89048d4703a">https://medium.com/@jake.page91/the-guide-to-git-i-never-had-a89048d4703a</a></p>
<p><a target="_blank" href="https://medium.com/@Choco23/git-merge-vs-git-rebase-selecting-the-appropriate-merge-strategy-863fc02a455c">https://medium.com/@Choco23/git-merge-vs-git-rebase-selecting-the-appropriate-merge-strategy-863fc02a455c</a></p>
<p><a target="_blank" href="https://gist.github.com/eashish93/3eca6a90fef1ea6e586b7ec211ff72a5?ref=dailydev">https://gist.github.com/eashish93/3eca6a90fef1ea6e586b7ec211ff72a5?ref=dailydev</a></p>
<p><a target="_blank" href="https://blog.prateekjain.dev/the-ultimate-guide-to-git-branching-strategies-6324f1aceac2">https://blog.prateekjain.dev/the-ultimate-guide-to-git-branching-strategies-6324f1aceac2</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/stop-breaking-your-codebase-the-git-hooks-nobody-told-you-about-b972a5576277">https://javascript.plainenglish.io/stop-breaking-your-codebase-the-git-hooks-nobody-told-you-about-b972a5576277</a></p>
<p><a target="_blank" href="https://www.linkedin.com/pulse/git-pruning-how-keep-your-repository-clean-efficient-mridul-u33ac/">https://www.linkedin.com/pulse/git-pruning-how-keep-your-repository-clean-efficient-mridul-u33ac/</a></p>
<p><a target="_blank" href="https://www.devshorts.in/p/coding-with-parallel-agents-and-git?utm_source=substack&amp;utm_medium=email">https://www.devshorts.in/p/coding-with-parallel-agents-and-git?utm_source=substack&amp;utm_medium=email</a></p>
<p><a target="_blank" href="https://medium.com/the-software-journal/the-most-misunderstood-git-feature-and-why-seniors-love-it-f7bbf4538d97">https://medium.com/the-software-journal/the-most-misunderstood-git-feature-and-why-seniors-love-it-f7bbf4538d97</a></p>
<p><a target="_blank" href="https://medium.com/the-software-journal/the-only-git-branching-strategy-that-works-in-real-teams-188c1c4c540b">https://medium.com/the-software-journal/the-only-git-branching-strategy-that-works-in-real-teams-188c1c4c540b</a></p>
<p><a target="_blank" href="https://dev.to/agentic-jj/i-looked-inside-git-and-you-wont-believe-what-i-found-actually-you-willcos-its-fascinating-1dp0">https://dev.to/agentic-jj/i-looked-inside-git-and-you-wont-believe-what-i-found-actually-you-willcos-its-fascinating-1dp0</a>?</p>
]]></content:encoded></item><item><title><![CDATA[Authentication and Authorization Handbook]]></title><description><![CDATA[Authentication and Authorization. In the context of access to APIs, authentication is the process of verifying the identity of a user who is making an API request (verifying who the user is), and authorization is the process of determining whether th...]]></description><link>https://blog.tuanhadev.tech/authentication-and-authorization-handbook</link><guid isPermaLink="true">https://blog.tuanhadev.tech/authentication-and-authorization-handbook</guid><category><![CDATA[authorization]]></category><category><![CDATA[authentication]]></category><category><![CDATA[JWT]]></category><category><![CDATA[OAuth2]]></category><category><![CDATA[token]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Tue, 22 Apr 2025 09:05:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/bMvuh0YQQ68/upload/6c0a1942c15af5878ee4184abbc47616.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Authentication and Authorization</strong>. In the context of access to APIs, authentication is the process of verifying the identity of a user who is making an API request (verifying who the user is), and authorization is the process of determining whether the user has the permission to access a particular API (verifying what a user is allowed to do).</p>
<p>In this blog, we will cover different types of authentication and authorization, best practices, and common mistakes.</p>
<h1 id="heading-comprehensive-explanation-of-session-cookie-and-jwt-on-the-entire-network">Comprehensive Explanation of Session, Cookie, and JWT on the Entire Network</h1>
<p>The HTTP protocol is a “<strong>stateless protocol”</strong>, that is, every time the server receives a request from the client, it is a completely new request, and the server does not know the historical request records of the client. The main purpose of a Session or Cookie is to make up for the stateless nature of HTTP.</p>
<h2 id="heading-what-is-the-session">What is the Session?</h2>
<p>When the client requests the server, the server will open up a “memory space” for this request. <mark>The memory space stores the Session object, and the storage structure is </mark> <code>ConcurrentHashMap</code>. The Session makes up for the nature of HTTP. The server can use a session to store the client's operation records during the same session.</p>
<h3 id="heading-how-do-we-determine-whether-it-is-the-same-session">How do we determine whether it is the same session?</h3>
<p>Because when the server receives the request for the first time, it opens up a session space (creates a Session object), and at the same time generates a sessionId, and sends the response to the client requesting to set a Cookie through the <code>Set-Cookie: JSESSIONID=XXX</code> command in the response header.</p>
<p>After the client receives the response, it sets a Cookie with information of <code>JSESSIONID=XXX</code> on the local client. The expiration time of this Cookie is the end of the browser session.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744876743753/ba7f9ce0-1b2c-4de5-b2cd-4a969ff98810.webp" alt class="image--center mx-auto" /></p>
<p>Next time, when the client sends the request to the same website each time, the request header will carry this Cookie information (including sessionId). Then, by reading the Cookie information in the request header, the server obtains the value named JSESSIONID and gets the sessionId of this request.</p>
<h3 id="heading-disadvantages-of-session">Disadvantages of Session</h3>
<p>However, the Session mechanism has a disadvantage. Suppose your server does load balancing and stores the Session on server A during the first request. Suppose the traffic to server A surges within a period of time, and requests will be forwarded to server B for access. However, server B does not store the session of server A, which will invalidate the session.</p>
<h2 id="heading-what-is-a-cookie">What is a Cookie</h2>
<p>You should have noticed that when introducing a Session, Cookie has already been mentioned. The session is implemented based on cookies. Session is stored on the server side, and the sessionId will be stored in the Cookie of the client.</p>
<p>Cookies in the HTTP protocol include Web Cookies and browser cookies. It is a small piece of data sent by the server to the web browser. The Cookie sent by the server to the browser will be stored in the browser and sent to the server together with the next request. Usually, it is used to determine whether two requests come from the same browser, such as when a user remains logged in.</p>
<p>Cookies are mainly used for the following three purposes:</p>
<p><strong><em>1. Session management</em></strong></p>
<ul>
<li>Cooperate with the server and identify user sessions by storing <code>sessionid</code>.</li>
</ul>
<p><strong><em>2. Store user information</em></strong></p>
<ul>
<li><p>Login status: Remember whether the user is logged in. No need to log in again on the next visit.</p>
</li>
<li><p>Preference settings: Such as language, theme, etc. Automatically apply on the next visit.</p>
</li>
</ul>
<p><strong><em>3. Track user behavior</em></strong></p>
<ul>
<li><p>Browsing history: Records visited pages for easy recommendation and navigation.</p>
</li>
<li><p>Analyze behavior: Understand user habits for optimization and precision marketing.</p>
</li>
</ul>
<h3 id="heading-creating-cookies">Creating Cookies</h3>
<p>When receiving an HTTP request from the client, the server can send a response with the Set-Cookie header. Cookies are usually stored by the browser, and then the Cookie is sent to the server along with the HTTP header.</p>
<h3 id="heading-set-cookie-and-cookie-headers">Set-Cookie and Cookie headers</h3>
<p>The <code>Set-Cookie</code> HTTP response header sends cookies from the server to the user agent. Here is an example of sending a Cookie.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744880129646/838a2ce1-f441-4d11-8db9-5f7927b27518.webp" alt class="image--center mx-auto" /></p>
<p>This header tells the client to store cookies.</p>
<p>Now, with each new request to the server, the browser will send all previously stored cookies back to the server using the Cookie header.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744880297779/342fa7e5-7cf1-45c4-a76f-c0af2bbb8e7c.webp" alt class="image--center mx-auto" /></p>
<p>There are two types of cookies. One is Session Cookies, and the other is Persistent Cookies. If a cookie does not contain an expiration date, it is regarded as a session cookie. Session cookies are stored in memory and are never written to disk. When the browser is closed, the cookie will be permanently lost thereafter. If a cookie contains an “expiration period“, it is regarded as a persistent cookie. At the specified expiration date, the cookie will be deleted from the disk.</p>
<h3 id="heading-session-cookie">Session Cookie</h3>
<p>The example above creates a session cookie. Session cookies have a characteristic that when the client closes, the cookie will be deleted because it does not specify the <code>Expires</code> or <code>Max-Age</code> directive.</p>
<p>However, web browsers may use session restoration, which will keep most session cookies in a permanent state as if the browser has never been closed.</p>
<h3 id="heading-permanent-cookies">Permanent Cookies</h3>
<p>Permanent cookies do not expire when the client is closed. Instead, they expire after a “specific date (Expires)” or a “specific length of time (Max-Age)”. For example.</p>
<p><code>Set-Cookie: id=a3fWa; Expires=Sat, 21 Sep 2024 11:28:00 GMT;</code></p>
<h3 id="heading-secure-and-httponly-flags-of-cookies">Secure and HttpOnly flags of cookies</h3>
<p>Secure cookies need to be sent to the server in an encrypted manner through the HTTPS protocol. Even if they are secure, sensitive information should not be stored in cookies because they are inherently insecure, and this flag does not provide real protection.</p>
<p>Function of HttpOnly</p>
<ul>
<li><p>The lack of the HttpOnly property in session cookies can lead to attackers being able to obtain users’ cookie information through programs (JS scripts, Applets, etc.), resulting in the leakage of users’ cookie information and increasing the threat of cross-site scripting attacks by attackers.</p>
</li>
<li><p>HttpOnly is an extension made by Microsoft for cookies. This value specifies whether cookies can be accessed through client scripts</p>
</li>
<li><p>If the HttpOnly property is not set to true in cookies, it may lead to cookie theft. Stolen cookies can contain sensitive information identifying site users, such as <a target="_blank" href="https://asp.net/">ASP.NET</a> session IDs or Forms authentication tickets. Attackers can replay stolen cookies to disguise themselves as users or obtain sensitive information and conduct cross-site scripting attacks.</p>
</li>
</ul>
<h3 id="heading-scope-of-cookies">Scope of cookies</h3>
<p>The <code>Domain</code> and <code>Path</code> identifiers define the scope of cookies: that is, which URLs cookies should be sent to.</p>
<p>The <code>Domain</code> identifier specifies which hosts can accept cookies. If not specified, the current host (excluding subdomains) is the default. If <code>Domain</code> is specified, subdomains are generally included.</p>
<p>For example, if <code>Domain=</code><a target="_blank" href="http://mozilla.org"><code>mozilla.org</code></a> is set, cookies are also included in subdomains (such as <a target="_blank" href="http://developer.mozilla.org"><code>developer.mozilla.org</code></a>).</p>
<p>For example, if <code>Path=/test</code> is set, the following addresses will all match:</p>
<ul>
<li><p><code>/test</code></p>
</li>
<li><p><code>/test/user/</code></p>
</li>
<li><p><code>/test/user/login</code></p>
</li>
</ul>
<h3 id="heading-why-do-we-need-a-token-when-we-have-already-had-a-session">Why do we need a token when we have already had a session?</h3>
<p>In modern web development, although sessions can realize user authentication and state management to a certain extent, they also have some limitations.</p>
<p>Suppose you are running a large online shopping mall. When users log in to your mall, the server will create a session to record the user’s login status. This Session is like an exclusive card prepared for users at the mall service desk, which records the user’s identity information.</p>
<p>However, when your mall’s business becomes busier and more users are shopping at the same time, the server needs to have this session information for each user, which will occupy a large amount of server memory resources. Moreover, if your mall uses multiple servers to share traffic (such as through a load balancer), then a complex mechanism is needed to ensure that when users switch between different servers, their Session information can be correctly transmitted and identified. Otherwise, users may be suddenly logged out or unable to shop normally.</p>
<p>In addition, suppose a user is shopping in your mall using a mobile phone and suddenly has an urgent matter and needs to go out. At this time, if the user uses another device (such as a tablet) to access your mall again outside, since the Session is usually bound to a specific device, the user may need to log in again, which will bring inconvenience to the user.</p>
<p><a target="_blank" href="https://javascript.plainenglish.io/10-cookie-facts-every-dev-should-know-8b4090e5fd6c">https://javascript.plainenglish.io/10-cookie-facts-every-dev-should-know-8b4090e5fd6c</a></p>
<h2 id="heading-what-is-a-token">What is a Token?</h2>
<p>Now, let’s introduce a token. The token is like a magic pass. After a user logs in successfully, the server will generate a token containing the user’s identity information and return this token to the user. The user can save this token on their own device.</p>
<p>When users browse products, add to the shopping cart, or check out in the mall, they only need to carry this token in each request. After the server receives the request, it can determine the user’s identity and permissions by verifying the validity of the Token, without having to look up and manage complex Session information.</p>
<p>For example, a user logs in to your mall on a mobile phone and obtains a Token. When the user goes out and uses a tablet to access the mall again, only this Token needs to be provided in the browser of the tablet, and the server can immediately identify the user’s identity without the user having to log in again. Moreover, no matter how many users are online at the same time in your mall, the server does not need to save a large amount of Session information for each user. It only needs to verify the Token for each request, greatly reducing the burden on the server.</p>
<p>In addition, Token can be easily integrated with third-party services. For example, if your mall wants to cooperate with an external payment service, only the Token needs to be passed to the payment service. The payment service can determine the user’s identity by verifying the Token without having to establish its own Session management mechanism.</p>
<h3 id="heading-access-token">Access Token</h3>
<p>Access Token is a resource credential required when accessing resource interfaces (APIs).</p>
<p>The composition of a token is not fixed. A simple token composition includes:</p>
<ul>
<li><p><code>uid</code> (user’s unique identity identifier);</p>
</li>
<li><p><code>time</code> (timestamp of the current time);</p>
</li>
<li><p><code>sign</code> (signature, a hexadecimal string of a certain length compressed by a hash algorithm from the first few digits of the token).</p>
</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">java</span><span class="hljs-selector-class">.security</span><span class="hljs-selector-class">.MessageDigest</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">java</span><span class="hljs-selector-class">.util</span><span class="hljs-selector-class">.Base64</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">java</span><span class="hljs-selector-class">.util</span><span class="hljs-selector-class">.Date</span>;

<span class="hljs-selector-tag">public</span> <span class="hljs-selector-tag">class</span> <span class="hljs-selector-tag">TokenGenerator</span> {

    public static String generateToken(int uid) {
        long time = new Date().getTime();
        String tokenContent = uid + "-" + time;
        // Generate a sign for the token content.
        String sign = generateSign(tokenContent);
        return uid + "-" + time + "-" + sign;
    }

    // <span class="hljs-selector-tag">Generate</span> <span class="hljs-selector-tag">a</span> <span class="hljs-selector-tag">sign</span> <span class="hljs-selector-tag">for</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">given</span> <span class="hljs-selector-tag">content</span> <span class="hljs-selector-tag">using</span> <span class="hljs-selector-tag">SHA-256</span> <span class="hljs-selector-tag">hash</span> <span class="hljs-selector-tag">algorithm</span>.
    <span class="hljs-selector-tag">private</span> <span class="hljs-selector-tag">static</span> <span class="hljs-selector-tag">String</span> <span class="hljs-selector-tag">generateSign</span>(<span class="hljs-selector-tag">String</span> <span class="hljs-selector-tag">content</span>) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(content.getBytes());
            StringBuilder hexString = new StringBuilder();
            for (byte <span class="hljs-attribute">b </span>: hash) {
                // Convert each byte to a two-digit hexadecimal string.
                String hex = Integer.<span class="hljs-built_in">toHexString</span>(<span class="hljs-number">0</span>xff &amp; b);
                if (hex.length() == 1) hexString.append('0');
                hexString.append(hex);
            }
            <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">hexString</span><span class="hljs-selector-class">.substring</span>(0, 8);
        } <span class="hljs-selector-tag">catch</span> (<span class="hljs-selector-tag">Exception</span> <span class="hljs-selector-tag">e</span>) {
            return null;
        }
    }

    <span class="hljs-selector-tag">public</span> <span class="hljs-selector-tag">static</span> <span class="hljs-selector-tag">void</span> <span class="hljs-selector-tag">main</span>(<span class="hljs-selector-tag">String</span><span class="hljs-selector-attr">[]</span> <span class="hljs-selector-tag">args</span>) {
        int uid = 1234;
        String token = generateToken(uid);
        System.out.println("Generated <span class="hljs-attribute">token</span>: <span class="hljs-string">" + token);
    }
}</span>
</code></pre>
<p>Output:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">Generated</span> <span class="hljs-selector-tag">token</span>: 1234<span class="hljs-selector-tag">-1729530432169-3638dd14</span>
</code></pre>
<p>It has the following characteristics:</p>
<ul>
<li><p>The server is stateless and has good scalability.</p>
</li>
<li><p>Supports mobile devices.</p>
</li>
<li><p>Sufficiently secure.</p>
</li>
<li><p>Supports cross-program invocations.</p>
</li>
</ul>
<p>The token authentication process:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744884092498/12e01e67-6db2-4254-832c-5da3dc55f793.webp" alt class="image--center mx-auto" /></p>
<p>From the above process, we can know that the token needs to be carried in every subsequent request, so the token needs to be placed in the HTTP Header. User authentication based on a token is a server-side, stateless authentication method, and the server does not need to store token data. The calculation time for parsing the token is exchanged for the storage space of the session, thereby reducing the pressure on the server and reducing frequent database query operations.</p>
<h3 id="heading-refresh-token">Refresh Token</h3>
<p>Refresh Token is another kind of token that is dedicated to refreshing the access token. If there is no refresh token, the access token can also be refreshed, but every time it’s refreshed, the user needs to enter the login username and password, which will be very troublesome. With the refresh token, this trouble can be reduced. The client directly uses the refresh token to update the access token without the user performing additional operations.</p>
<p>The validity period of the Access Token is usually relatively short. When the Access Token becomes invalid due to expiration, a new token can be obtained by using the Refresh Token. If the Refresh Token also expires, the user can only log in again.</p>
<p>In addition, the Refresh Token and expiration time are stored in the server’s database and are only verified when applying for a new Access Token. It will not affect the response time of business interfaces and does not need to be kept in memory all the time, like Session, to handle a large number of requests.</p>
<h1 id="heading-authentication">Authentication</h1>
<p>There are many ways to do API Authentication, such as basic auth, API Keys, JWT, OAuth, etc, and each has its benefits and trade-offs. There is no “one size fits all“ to the question “What is the best API authentication method?“, It has its own idea use cases. So, the best practice in deciding which authentication method to use is “it depends“, not simply “choose the best for everything“.</p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/how-to-implement-zero-trust-authentication-in-your-web-apps/?ref=dailydev">https://www.freecodecamp.org/news/how-to-implement-zero-trust-authentication-in-your-web-apps/?ref=dailydev</a></p>
<h2 id="heading-http-basic-authentication-basic-auth">HTTP Basic Authentication (Basic Auth)</h2>
<p>When we talk about authentication, we have to start with HTTP basic authentication, because, as the name suggests, it’s the most “basic” way to implement API authentication. We put base64-encoded <code>user:password</code> pairs in the <code>Authorization</code> header field and send it over the internet. Since base64 is encoding, not hashing or encryption, this method is insecure by default, unless it is used with HTTPS.</p>
<p>However, the insecure nature of basic auth doesn’t necessarily mean it’s useless:</p>
<ul>
<li><p>In highly controlled internal networks where no north-south internet traffic is allowed, external access is completely blocked, and network traffic is monitored, basic auth over HTTP might be used(however, even in such environments, one of the best practices is to use HTTPS for better security)</p>
</li>
<li><p>Basic authentication over HTTP might be used for simplicity in local development or for debugging and testing in a tightly controlled environment.</p>
</li>
<li><p>When some entry-level protection over non-sensitive data is needed, like if we are exposing some metrics of our app but we don’t want everybody to access it except for Prometheus to scrape it, we can use basic auth to protect the metrics endpoint, and configure basic auth in the <code>[scrape_config</code>](<a target="_blank" href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/?ref=blog.gitguardian.com#scrape_config">https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config</a>) of Prometheus.</p>
</li>
<li><p>When we don’t need to handle HTTPS on a per-service basis, and HTTPS is handled in general, like by a service mesh.</p>
</li>
</ul>
<h2 id="heading-api-keys">API Keys</h2>
<p>An API key is a unique identifier (like a user/password pair) issued by an API provider and linked to users for access control. Similar to basic auth, it’s not secure unless it’s transmitted over HTTPS.</p>
<p>Like basic auth, the API Key over HTTP could only be used in a controlled environment. But unlike basic auth, API key, as the name suggests, offers access to APIs, and APIs oftentimes need to be exposed to external networks. So, use HTTPS with API Key authentication whenever possible.</p>
<p>Since the API key is similar to a basic auth credential or user/password, one of the best practices is to treat it like a password: Rotate it regularly. Even if we do so, it’s still relatively long-term, so another best practice is to use temporary security credentials whenever possible: before creating some keys and start hacking, review alternatives to long-term access keys that are mentioned in the following sections.</p>
<p>If we choose to use an API key for authentication, there is one more best practice to follow: The API key must be used with every request.</p>
<p>But how?</p>
<p>Although we can set it in the query string, we shouldn’t: web servers and browser histories often log URLs, including query parameters. This means our API key could be stored in various log files, making it accessible to anyone with access to those logs. The best practice here is to transmit API keys in the <code>Authorization</code> header, typically using the <code>Bearer</code> scheme: <code>Authorization: Bearer YOUR_API_KEY</code>. Like passwords, API keys should not be stored in plaintext but securely hashed.</p>
<h2 id="heading-json-web-token-jwt">JSON Web Token (JWT)</h2>
<h3 id="heading-what-is-jwt">What is JWT?</h3>
<p>JSON Web Token (shortened to JWT) acts like a digital handshake between two participants, say you and a website. It’s a compact and secure method that ensures both parties can trust the exchanged information.</p>
<p>Here’s what the JWT looks like:</p>
<p><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpYXQiOjE2OTg2ODg0OTksIm5hbWUiOiJEZXZ0cm92ZXJ0Iiwic3ViIjoidGhpcyBpcyBhIHN1YmplY3QifQ. NT2JhQ9oLc_HIZB6WW8yAaxSHcZ8QvNE1H0C5Adhmrg</code></p>
<p>You will notice it’s split into 3 sections, each separated by dots(.)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744956622509/cedbf946-e309-4aac-b151-9e2cfaf608b0.webp" alt class="image--center mx-auto" /></p>
<p>The JWT acts as proof of who you are online:</p>
<p>Because it’s made in a special way, it’s tough for others to fake it. Plus, only websites that have the “right“ key can understand it. This is great for times when you log into a website and use different parts of it without having to log in again and again.</p>
<h3 id="heading-structure-of-jwt">Structure of JWT</h3>
<p>A JWT technically consists of three parts separated by dots (.), which are:</p>
<p><strong>Header</strong></p>
<p>Starting with the first chunk before the dot, we have the Header. This is encoded using Base64 and reveals both the type of token and the algorithm behind the signature.</p>
<p>A quick look:</p>
<pre><code class="lang-typescript">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
=
{
  <span class="hljs-string">"alg"</span>: <span class="hljs-string">"HS256"</span>, <span class="hljs-comment">// the signature's algorithm</span>
  <span class="hljs-string">"typ"</span>: <span class="hljs-string">"JWT"</span>    <span class="hljs-comment">// the token type</span>
}
</code></pre>
<p><strong>Payload</strong></p>
<p>Moving to the middle, between those two dots, we encounter the Payload, which is also a Base64 encoded section.</p>
<p>Within the payload, you will find the “claims“, which are the tidbits of information, maybe the user’s ID or their email address.</p>
<p>Speaking of claims, they come in three flavors: registered, public, and private. Here is a brief look:</p>
<pre><code class="lang-typescript">eyJpYXQiOjE2OTg2ODg0OTksIm5hbWUiOiJEZXZ0cm92ZXJ0Iiwic3ViIjoidGhpcyBpcyBhIHN1YmplY3QifQ
=
{
  <span class="hljs-string">"iat"</span>: <span class="hljs-number">1698688499</span>,
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"Devtrovert"</span>,
  <span class="hljs-string">"sub"</span>: <span class="hljs-string">"this is a subject"</span>
}
</code></pre>
<p>A word of caution: It’s best to avoid putting the sensitive info in the payload, even though the JWT ensures the data hasn’t been changed, it doesn’t hide the content.</p>
<p>Now let’s explore those other claims further.</p>
<p>**Registered<br />**Let’s kick things off with registered claims.</p>
<p>They’re a bunch of predefined bits of information that the JWT standard provides for our benefit, while you don’t have to use them, it’s a good practice to do so:</p>
<ul>
<li><p><strong>iss (issuer)</strong>: Think of this as the “author” of the JWT (e.g., “iss”: “<a target="_blank" href="http://auth.devtrovert.com">auth.devtrovert.com</a>”).</p>
</li>
<li><p><strong>sub (subject)</strong>: This is all about who the JWT is about, often pointing to a specific user (e.g. “sub”: “john-handsome”).</p>
</li>
<li><p><strong>aud (audience)</strong>: Who should be reading the JWT? It could be meant for one entity or many (e.g. “aud”: “example-app”).</p>
</li>
<li><p><strong>exp (expiration time):</strong> Simply put, when does this JWT expire? It counts seconds since the Epoch time (e.g., “exp”: 1583241600).</p>
</li>
<li><p><strong>nbf (not before time)</strong>: It tells when we can start using the JWT, using a similar time format as exp. (e.g. “nbf”: 1583241600).</p>
</li>
<li><p><strong>iat (issued at time)</strong>: This is just when the JWT was made, like a timestamp of its creation (e.g. “iat”: 1583241600).</p>
</li>
<li><p><strong>jti (JWT ID)</strong>: A special ID for the JWT, which can be handy for various purposes like keeping track or ensuring it’s used only once.(e.g. “jti”: “a1234567”).</p>
</li>
</ul>
<p>These are part of the JWT standard.</p>
<p>So, when you decide to use them, it’s wise to stick to the standard’s rules, even if they’re <strong>optional</strong>.</p>
<p>**Public<br />**Public claims are the ones you can set yourself.</p>
<p>But, because you don’t want to accidentally use the same claim name as someone else (or registered claims), it’s a neat idea to use a web address-like format.</p>
<p>Here’s what I mean:</p>
<pre><code class="lang-typescript"><span class="hljs-string">"http://example.com/roles"</span>: [<span class="hljs-string">"editor"</span>, <span class="hljs-string">"subscriber"</span>]
</code></pre>
<p>By using this structure, we make sure our “roles” claim is its own unique thing and doesn’t collide with any other “roles” claim out there.</p>
<p>**Private<br />**Private claims are claims that you make up to suit your app’s specific needs and they aren’t meant for the public, and there’s no official list of them anywhere.</p>
<blockquote>
<p><em>“Hold up… If they’re called ‘private’, why can everyone read them?”</em></p>
</blockquote>
<p>Good point, it’s a naming thing, despite the name, private claims aren’t secrets.</p>
<p>When we look inside a JWT, everything, both public and private claims, is out in the open because of how JWTs are encoded, so anyone with the right tools can see them.</p>
<p>The terms “public” and “private” in the context of JWT claims don’t refer to their visibility or their encryption status:</p>
<ul>
<li><p><strong>Public Claims</strong>: These are commonly understood claims, using a web URL format for naming helps keep things organized and avoids confusion.</p>
</li>
<li><p><strong>Private Claims</strong>: These are your special additions, tailored just for your app, and they get the “private” label because they’re all about your app’s unique needs</p>
</li>
</ul>
<p>For instance, having a claim like <code>“department”: “HR”</code> might mean the person associated with the JWT works in Human Resources.</p>
<p><strong>Signature</strong></p>
<p>This is the third part of our JWT, right after the last dot, we encounter the signature.</p>
<p>What is fascinating about this piece is that it’s constructed by joining the header and the payload, then encrypting this merged data using a secret key. This signature ensures that our data remains untouched and authentic during its… journey.</p>
<p>For a hands-on perspective, imagine the process like this:</p>
<pre><code class="lang-typescript">NT2JhQ9oLc_HIZB6WW8yAaxSHcZ8QvNE1H0C5Adhmrg
=
HMACSHA256(
base64UrlEncode(header) + <span class="hljs-string">"."</span> +
base64UrlEncode(payload),
secret)
</code></pre>
<p>When pieced together, our JWT presents itself as:</p>
<p><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpYXQiOjE2OTg2ODg0OTksIm5hbWUiOiJEZXZ0cm92ZXJ0Iiwic3ViIjoidGhpcyBpcyBhIHN1YmplY3QifQ. NT2JhQ9oLc_HIZB6WW8yAaxSHcZ8QvNE1H0C5Adhmrg</code></p>
<p>Now, any server that verifies this token has the secret key, which is “my secret“ in this example. Unlike me, you better don’t share it with anyone.</p>
<p>This equips the server to decipher the signature and confirm the authenticity of the header and payload.</p>
<h3 id="heading-a-dip-into-algorithms">A Dip into Algorithms</h3>
<p>As we are on the topic of cryptographic algorithms, it might be a good moment to share some basics about two algorithm types.</p>
<ul>
<li><p><strong>Symmetric</strong>: A single key is used for both operations. For encryption, it means both encryption and decryption, or both creating a signature and verifying it. Both parties (sender and receiver) must process and protect this secret key. In the content of JWTs, typically, only the server retains this secret key.</p>
</li>
<li><p><strong>Asymmetric</strong>: This involves a key pair: a public key and a private key. For encryption, the public key encrypts, and its corresponding private key decrypts. For digital signatures, the private key is used to sign (create a signature), and the public key is used to verify the signature.</p>
</li>
</ul>
<p>Now, there are 3 common algorithms used to sign and verify the JWTs:</p>
<ul>
<li><p><strong>HMAC (Symmetric)</strong>: Uses a single secret key to create and check a signature for data; only the server holds this key to confirm the data hasn’t been changed in transit. For JWTs, HMAC combined with SHA-256 hashing is common, known as HS256.</p>
</li>
<li><p><strong>RSA (Asymmetric)</strong>: Works with two keys: a public key and a private key. While you might hear about encrypting data with the public key and decrypting it with the private one, for JWTs, it’s a bit different. Here, the private key signs the token, and the public key checks its authenticity.</p>
</li>
<li><p><strong>ECDSA (Asymmetric)</strong>: This is a newer method for making digital signatures. While RSA is widely used, ECDSA can offer the same safety but is faster and needs shorter keys, which makes it a good choice for systems where speed and saving space are important.</p>
</li>
</ul>
<h3 id="heading-how-jwts-are-used-in-authentication">How JWTs are used in Authentication</h3>
<p>Let’s break down how JWTs play a vital role in the authentication process step by step:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744963356868/0ff42284-13d6-4c25-9e4a-8493fa46e702.webp" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Logging In</strong>: A user enters their username and password, the server checks these details against its records.</p>
</li>
<li><p><strong>JWT creation</strong>: If the server confirms the user’s details are correct, it creates a JWT. This token contains the user’s details and other important information (but not sensitive). Then, the server signs this token with a secret key, ensuring its security.</p>
</li>
<li><p><strong>Sending the Token</strong>: The server sends the token back to the user, this usually happens in the HTTP header for easy retrieval and usage in subsequent requests.</p>
</li>
<li><p><strong>Token in Action</strong>: Whenever the user wants to access something on the server, they send this token back. They typically add it to their request headers, like a special access pass.</p>
</li>
<li><p><strong>Server verification</strong>: When the server receives a request with a token, it verifies the token’s authenticity. It checks if the signature matches and then gets the user’s details from the token to process the request.</p>
</li>
<li><p><strong>Response to the client</strong>: After validating the token and processing the request, the server sends the needed data back to the user.</p>
</li>
</ol>
<p>One of the great things about JWTs is that they allow stateless authentication. What does this mean?</p>
<p>Well, the server doesn’t need to remember or store every token. Each token is self-contained, carrying all the info the server need to identify the user.</p>
<h3 id="heading-how-the-jwt-token-is-checked">How the JWT token is checked?</h3>
<p>When the user sends a token to the server, how does the server know it’s valid? Let’s go through that process:</p>
<ol>
<li><p>Validate the Token structure: Our server looks at the token to see if it has the right format, it should have three parts: the Header, the Payload, and the Signature (structured like ‘xxxxx.yyyyy.zzzzz’).</p>
</li>
<li><p>Decoding: Our server then decodes the token, since in’s usually in Base64URL format, decoding it lets the server see the Header and the Payload’s details:</p>
</li>
<li><p>Figuring Out the Algorithm: By checking the token’s header, the sever can see which algorithm was used to sign the token.</p>
</li>
<li><p>Matching Signatures: The server then tries to recreate the token’s signature. If the new signature matches the one in the received token, it shows the token hasn’t been changed or tampered with.</p>
</li>
<li><p>Checking the Claims: Lastly, the server examines the JWT’s standard claim. It looks at timestamps and identifiers like when the token expires (‘exp’), when it starts being valid (‘nbf’), when it was made (‘iat’), who made it (‘iss’), who it’s for (‘aud’), and who it’s about (‘sub’).</p>
</li>
</ol>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*RzixBLp3M5VQTTf1hpAXwg.png" alt /></p>
<h3 id="heading-pitfalls-of-jwt">Pitfalls of JWT</h3>
<p>While JWT offers many advantages, it’s essential to be aware of potential pitfalls and security concerns that can arise if it’s not implemented properly.</p>
<p>Here are some key issues associated with JWT tokens:</p>
<ul>
<li><p>Security Risks from Improper Algorithm Choice: There are different ways to encrypt JWTs. If the encryption method isn’t properly chosen or implemented, it can be vulnerable to attack.</p>
</li>
<li><p>Key Management is an Issue: If the secret key used to create and verify JWTs is compromised, attackers could forge tokens and gain unauthorized access.</p>
</li>
<li><p>Revocation Challenges: It can be tricky to revoke a JWT once it’s been issued. This means that if a user’s credentials are compromised, their token might still be valid.</p>
</li>
<li><p>Bypassing Signature Verification: Vulnerabilities in certain JWT libraries and implementations allow for signature verification to be bypassed. These vulnerabilities could enable attackers to create forged tokens that appear legitimate to the application.</p>
</li>
</ul>
<h3 id="heading-5-common-mistakes-developers-make-with-jwt-authentication">5 Common Mistakes Developers Make with JWT Authentication</h3>
<p>Most developers think API authentication is simple:<br />User logs in → server issues JWT → client stores token → done.</p>
<p>That’s the story in every quick-start tutorial. But in the real world, things aren’t that clean.<br />Tokens leak. Sessions don’t expire. Refresh endpoints are abused.</p>
<p>And before you realize it, your “secure API” is quietly allowing anyone with the right token to impersonate users indefinitely.</p>
<p>Authentication isn’t about just verifying credentials; it’s about managing identity <em>safely</em> over time.<br />Here are the <strong>five most common mistakes</strong> developers make when handling API authentication and how to fix them the right way.</p>
<ol>
<li><strong>Storing Tokens in the Wrong Place</strong></li>
</ol>
<p>Let’s start with the classic.</p>
<p>Most developers do this after login:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"token"</span>, accessToken);
</code></pre>
<p>It works, it’s convenient, and it’s insecure.</p>
<p><strong>Why It’s Dangerous</strong></p>
<p>Anything stored in <code>localStorage</code> or <code>sessionStorage</code> can be accessed by <strong>JavaScript running on your page</strong>.<br />If your app ever suffers from XSS (Cross-Site Scripting), an attacker can simply run:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"token"</span>));
</code></pre>
<p>Boom, your user’s session is gone.</p>
<p><strong>The Correct Way</strong></p>
<ul>
<li><p>Store <strong>short-lived access tokens in memory only</strong> (React context, Redux, or a variable).</p>
</li>
<li><p>Store <strong>refresh tokens in HTTP-only cookies,</strong> which can’t be read by JavaScript.</p>
</li>
<li><p>Use CSRF tokens to prevent cross-site attacks.</p>
</li>
</ul>
<p>Example (Express):</p>
<pre><code class="lang-javascript">res.cookie(<span class="hljs-string">"refreshToken"</span>, token, {
  <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">secure</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">sameSite</span>: <span class="hljs-string">"Strict"</span>,
});
</code></pre>
<p>This makes token theft via scripts nearly impossible.</p>
<ol start="2">
<li><strong>Using Long-Lived Tokens</strong></li>
</ol>
<p>Developers often set JWTs to expire in days or even weeks because re-authentication feels “inconvenient.”<br />But long-lived tokens are like giving out permanent keys; once leaked, they never expire.</p>
<p><strong>Real-World Risk</strong></p>
<p>A token valid for 30 days gives attackers a huge window to exploit it. Even if you patch the vulnerability tomorrow, the stolen token still works.</p>
<p><strong>The Fix</strong></p>
<p>Adopt <strong>short-lived access tokens</strong> (10–30 minutes) and <strong>long-lived refresh tokens</strong>.<br />When the access token expires, issue a new one via the refresh token.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> accessToken = jwt.sign({ <span class="hljs-attr">id</span>: user.id }, JWT_SECRET, { <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">"15m"</span> });
<span class="hljs-keyword">const</span> refreshToken = jwt.sign({ <span class="hljs-attr">id</span>: user.id }, JWT_SECRET, { <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">"7d"</span> });
</code></pre>
<p>Short expiration windows dramatically reduce the damage from token leaks.</p>
<ol start="4">
<li><strong>Treating JWTs as “Stateless Forever”</strong></li>
</ol>
<p>JWTs are stateless, that’s their beauty and their curse.<br />Developers love that they don’t have to check a database on every request. But that also means <strong>you can’t revoke them easily</strong>.</p>
<p><strong>Common Oversight</strong></p>
<p>If a user logs out or a token leaks, there’s often no way to invalidate it until it expires.<br />Attackers with old tokens can continue making valid requests for hours or days.</p>
<p><strong>The Right Way to Handle It</strong></p>
<p>Implement <strong>token rotation and revocation</strong>.</p>
<ul>
<li><p>Track issued refresh tokens in your database.</p>
</li>
<li><p>When a refresh token is used, mark it as “used” and generate new tokens.</p>
</li>
<li><p>If an old refresh token reappears, block the session immediately.</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (refreshToken.used) {
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Token reuse detected"</span>);
}
refreshToken.used = <span class="hljs-literal">true</span>;
<span class="hljs-keyword">await</span> save(refreshToken);
</code></pre>
<p>This ensures that each token can be used only once, a key defense against replay attacks.</p>
<ol start="5">
<li><strong>Ignoring Token Claims and Validation</strong></li>
</ol>
<p>A shocking number of APIs verify JWT signatures but ignore the claims inside them.<br />That’s like checking someone’s ID but not reading the name.</p>
<p><strong>Common Mistake</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> payload = jwt.verify(token, process.env.JWT_SECRET);
<span class="hljs-comment">// OK ✅ but missing claim validation!</span>
</code></pre>
<p>If you don’t verify the <strong>issuer (</strong><code>iss</code><strong>)</strong>, <strong>audience (</strong><code>aud</code><strong>)</strong>, or <strong>expiration (</strong><code>exp</code><strong>)</strong>, Any valid token signed with the same secret can be reused, even from another service.</p>
<p><strong>How to Fix It</strong></p>
<p>Always verify the token context:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> payload = jwt.verify(token, process.env.JWT_SECRET, {
  <span class="hljs-attr">audience</span>: <span class="hljs-string">"myapi.com"</span>,
  <span class="hljs-attr">issuer</span>: <span class="hljs-string">"auth.myapi.com"</span>,
});
</code></pre>
<p>And double-check <code>exp</code> and <code>nbf</code> timestamps to ensure the token isn’t expired or not yet valid.</p>
<p><strong>Pro Tip:</strong> Rotate JWT secrets periodically. A leaked signing key can compromise your entire system.</p>
<ol start="5">
<li><strong>Forgetting About Revocation and Logout</strong></li>
</ol>
<p>One of the biggest myths in modern auth:</p>
<blockquote>
<p><em>“JWTs don’t need logout just let them expire.”</em></p>
</blockquote>
<p>That’s fine in theory, but in production, users log out, passwords change, and security incidents happen.</p>
<p>Without a proper revocation system, old tokens remain valid until expiry, and that’s dangerous.</p>
<p><strong>The Solution</strong></p>
<p>Maintain a <strong>revoked token store</strong> (a simple table or Redis cache) keyed by <code>jti</code> (JWT ID).</p>
<p>When a user logs out or resets their password:</p>
<ol>
<li><p>Add their tokens <code>jti</code> to the revoked list.</p>
</li>
<li><p>Check this list during every authentication step.</p>
</li>
</ol>
<p>Example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> (revokedTokens.has(payload.jti)) {
  <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">401</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Token revoked"</span> });
}
</code></pre>
<p>This tiny step prevents reusing stolen or expired tokens.</p>
<h2 id="heading-openid-connect-oidc">OpenID Connect (OIDC)</h2>
<p>OpenID Connect is an identity layer on top of the OAuth 2.0 protocol. It extends the OAuth 2.0 standard to standardize a way for authentication.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1000/1*oFe0Jr3Y-s46834I4CI9YQ.png" alt="OpenID Connect extending OAuth 2.0" /></p>
<p>The difference between the two is that OAuth 2.0 provides authorization, while OIDC provides authentication.</p>
<p>OpenID Connect enables an Internet identity ecosystem for easy and secure integration. For example, if a user wants to create an account at a new website, they may use Google to create their account rather than creating an account on the new website. The OpenID provider (Google, in this case) handles the authentication processes and obtains the user’s consent to provide specific information, such as a user profile, to the relying party (the new website, in this case).</p>
<p>OAuth does not provide the user identity right away, but rather it provides an access token for authorization. OpenID Connect enables the client to identify the user based on authentication performed by the authorization server. This is achieved by defining a scope named <code>openid</code> when requesting the authorization server for user login and consent. <code>openid</code> is a mandatory scope to tell the authorization server that OpenID Connect is required.</p>
<p>The URI for the OpenID Connect authentication request made by the client looks like this:</p>
<pre><code class="lang-typescript">https:<span class="hljs-comment">//accounts.google.com/o/oauth2/v2/auth?</span>
 response_type=code&amp;
 client_id=your_client_id&amp;
 scope=openid%<span class="hljs-number">20</span>contacts&amp;
 redirect_uri=https%<span class="hljs-number">3</span>A<span class="hljs-comment">//oauth2.example.com/code</span>
</code></pre>
<p>The result of the request is an authorization code that the client can exchange for an access token and ID token. If the OAuth flow is implicit, then the authorization server responds with an access token and an ID token right away.</p>
<p>The ID token is a JWT or JSON Web Token. A JWT is an encoded token that consists of three parts: header, payload, and signature. After acquiring the ID token, the client can decode it to get the user info encoded in the payload part, like this:</p>
<pre><code class="lang-typescript">{
  <span class="hljs-string">"iss"</span>: <span class="hljs-string">"https://accounts.google.com"</span>,
  <span class="hljs-string">"sub"</span>: <span class="hljs-string">"10965150351106250715113082368"</span>,
  <span class="hljs-string">"email"</span>: <span class="hljs-string">"johndoe@example.com"</span>,
  <span class="hljs-string">"iat"</span>: <span class="hljs-number">1516239022</span>,
  <span class="hljs-string">"exp"</span>: <span class="hljs-number">1516242922</span>
}
</code></pre>
<h3 id="heading-claims"><strong>Claims</strong></h3>
<p>The payload of the ID token contains some fields known as claims. Basic claims are:</p>
<ul>
<li><p><code>iss</code> token issuer.</p>
</li>
<li><p><code>sub</code> unique identifier for the user.</p>
</li>
<li><p><code>email</code> user’s email.</p>
</li>
<li><p><code>iat</code> token issuing time is represented as Unix time.</p>
</li>
<li><p><code>exp</code> token expiration time represented as Unix time.</p>
</li>
</ul>
<p>However, claims are not limited to these fields. It’s up to the authorization server to encode claims. The client can use this information to authenticate the user.</p>
<p>If the client needs more user information, the client can specify standard OpenID Connect scopes to tell the authorization server to include the required information in the ID token’s payload. These scopes are <code>profile</code>, <code>email</code>, <code>address</code>, and <code>phone</code>.</p>
<h2 id="heading-multi-factor-authentication-mfa">Multi-Factor Authentication (MFA)</h2>
<p>MFA significantly enhances security by requiring “multiple factors.“ (hence the name, Multi-Factor) for authentication. In practice, this can be combined with other authentication methods for high-risk operations or sensitive data. It can be used to secure the authentication at the IDP level in OIDC.</p>
<h2 id="heading-single-sign-on">Single Sign-On</h2>
<p><a target="_blank" href="https://medium.com/@techworldwithmilan/how-does-single-sign-on-sso-work-31ffa1afcc63">https://medium.com/@techworldwithmilan/how-does-single-sign-on-sso-work-31ffa1afcc63</a></p>
<h3 id="heading-what-is-sso">What is SSO?</h3>
<p>Single Sign-On (SSO) is a technology that allows users to securely authenticate to multiple applications and sites at once using a single set of credentials and seamlessly move between them without re-authentication.</p>
<p>SSO authentication begins when a user logs in to one of the clients associated with SSO. Instead of entering the username and password for each service each time, the user does so once. The data creates a unique session that other services will recognize.</p>
<p>When a user attempts to access another service or application within SSO, the service asks the IdP to confirm the user’s authentication. Instead of asking for credentials again, the service accepts the token that proves that the user has already been authenticated.</p>
<p>SSO is a part of a more general Identity and Access Management (IAM) concept. This comprehensive system covers the processes used to manage the user identities and their access to various resources.</p>
<p>All aspects of an IAM system can be divided into three groups: user experience, security, and infrastructure.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745135346768/b965204d-8525-4e4d-8a31-9b5558abc1ba.webp" alt class="image--center mx-auto" /></p>
<p>SSO implementation is based on protocols such as OAuth, Open ID Connect, and SAML (Security Assertion Markup Language). SAML is also beyond the scope of this material since this standard is still more commonly used in corporate SSO solutions. Therefore, we will only focus on the definition to understand the difference.</p>
<p>SAML is an XML-based standard for exchanging authentication and authorization data between an identity provider and a service provider.</p>
<h3 id="heading-sso-implementation-scheme">SSO implementation scheme</h3>
<p>We have already become acquainted with the OAuth and OpenID protocols, so let’s immediately schematically consider one of the examples of SSO implementation in practice. Since we want to get end-to-end authentication both in web applications and on mobile clients, we default to auth code flow with PKCE as a basis, and get approximately the following picture: where to begin with, each client needs to be integrated with the IdP.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:700/1*asMxQ8XBnuvTqqaNGN9BQw.png" alt /></p>
<p>Schematically, the algorithm for SSO operation between services can be described as follows:</p>
<ol>
<li><p>The user wants to log in to one of the hosts using SSO</p>
</li>
<li><p>The standard OAuth 2.0 path occurs, in which the user is redirected to the authorization form on the IdP (Identity Provider) host when they enter their login data.</p>
</li>
<li><p>Then, the redirect to the target client occurs, where, according to the standard, the services exchange the received code for a set of tokens. At the same time, before the redirect, the IDP also saves the user’s session on its domain (for example, in cookies).</p>
</li>
<li><p>The user wants to log in to another service using this IDP.</p>
</li>
<li><p>The client redirects the user to the authorization page on the IdP. Still, the provider will immediately “catch” the previous session because it has been on the IdP host since the previous authorization in the user UA (browser).</p>
</li>
<li><p>Then, according to the PKCE flow, the user will be redirected back to the client with the code without entering a login/password.</p>
</li>
<li><p>The user will be authorized in the same way as on client 1</p>
</li>
</ol>
<p>That’s it. SSO, at minimum, is ready. Of course, provided that you have, for example, a microservice architecture and some services are located on one host, you can move part of the authorization and exchange of code for a set of tokens to a separate service and leave only refresh in the rest.</p>
<h1 id="heading-authorization">Authorization</h1>
<p>Authorization verifies that the user is allowed to do. Let’s start with one of the most common authorization methods in everyday use: OAuth.</p>
<h2 id="heading-oauth-20">OAuth 2.0</h2>
<p>OAuth (Open Authorization) is a token-based authorization mechanism that enables users to grant third-party apps access to their data without having to share their login credentials. With greater flexibility and scalability than OAuth 1.0, OAuth 2.0 replaced 1.0 in 2012 and is now the de facto standard for online authorization.</p>
<p>For example, I use my Garmin fitness app (resource server and authorization server) to track my daily workouts, and now I want to create a new app, “Nutriplan“ (the client), to monitor my nutrition and calorie intake and consumption. In this case:</p>
<ul>
<li><p>The Nutriplan app asks for access to resources on the Garmin app, which is granted by the user logging in to the Garmin app with their user/password, but the user/password is not shared with the Nutriplan.</p>
</li>
<li><p>An authorization code is created and shared with Nutriplan. However, the authorization code can’t be used to access user data in the Garmin app.</p>
</li>
<li><p>With the authorization code, the Nutriplan app requests an access token from the Garmin app’s authorization server endpoint.</p>
</li>
<li><p>The Nutriplan client uses the access token to access my resources on the Garmin app to recommend nutrition plans according to my fitness data in the Garmin app.</p>
</li>
</ul>
<p>During the whole process, my Garmin app login password isn’t shared with Nutriplan but my data in my Garmin app is shared securely with third-party apps, access delegation without sharing credentials.</p>
<h2 id="heading-scope-based-authorization">Scope-Based Authorization</h2>
<p>OAuth 2.0 uses a scope-based authorization, where specific permissions are defined in scopes as a way to limit the amount of access that is granted into an access token. For example, an access token issued to a client app may be granted READ and WRITE access to protected resources, or just READ access. The client requests a scope during the authorization process and the user can then grant or deny these permissions.</p>
<h2 id="heading-role-based-access-control-rbac">Role-Based Access Control (RBAC)</h2>
<p>Role-Based Access Control (RBAC) is a method of regulating access to resources based on the roles of individual users. By assigning users to roles (e.g, admin, editor, viewer) and defining different permissions for each role, RBAC simplifies permission management and improves security. There are some generally accepted good practices for using RBAC.</p>
<ul>
<li><p>Least Privilege: Minimal and only explicitly required permissions should be assigned to roles, and start with a default deny policy and explicitly grant permissions only where needed.</p>
</li>
<li><p>Clearly define roles: Create roles that represent specific job functions or responsibilities within the organization, and avoid creating roles that are too broad or too narrow. Keep the number of roles to a minimum; too many roles can lead to complexity and difficulty in managing permissions. Consider using role hierarchies to simplify management.</p>
</li>
<li><p>Periodic review, audit, and documentation: Conduct regular security audits to stay up-to-date and identify potential vulnerabilities; maintain clear and comprehensive documentation of our RBAC policies and procedures.</p>
</li>
</ul>
<h2 id="heading-attribute-based-access-control-abac">Attribute-Based Access Control (ABAC)</h2>
<p>ABAC provides finer-grained control by passing access decisions on not just the generic role, but detailed attributes of the user, resource, and environment. It is therefore more flexible than RBAC, but the tradeoff is that it’s more complex to implement.</p>
<p>For complex scenarios, we can consider integrating ABAC principles with RBAC to provide dynamic and context-aware access control.</p>
<h2 id="heading-policy-based-access-control-pbac">Policy-Based Access Control (PBAC)</h2>
<p>PBAC is a strategy for managing user access where the roles of users are combined with policies to determine what access privileges users of each role should have. PBAC can be used with RBAC/ABAC together. Cloud IAM users should already be familiar with roles and policies. PBAC offers several benefits over the traditional access control model, like RBAC.</p>
<ul>
<li><p>Finer-grained: Like ABAC, PBAC allows for highly granular control over access based on a wide range of attributes or conditions. We can define policies based on both user and resource attributes.</p>
</li>
<li><p>Attribute-Based Access Control (ABAC) Integration: PBAC is often used in conjunction with ABAC, allowing for even more flexible and expressive control.</p>
</li>
<li><p>Dynamic Access Control: PBAC enables dynamic access control decisions based on real-time conditions. Access can be granted or revoked automatically based on changes in user attributes, resource attributes, or environmental factors. This allows for more flexible and adaptive security policies.</p>
</li>
</ul>
<h1 id="heading-conclusion">Conclusion</h1>
<p>This material helped you learn something new and organize your existing knowledge. Please remember that specifications and standards, no matter how inconvenient and optimal they may seem, are written by professionals who have spent much time and effort searching for an optimal solution and closing security holes. Take your time with implementation immediately, and spend time studying the documentation and the subject matter.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://levelup.gitconnected.com/the-http-protocol-is-a-stateless-protocol-that-is-every-time-the-server-receives-a-request-b9c4f31bfbb3">https://levelup.gitconnected.com/the-http-protocol-is-a-stateless-protocol-that-is-every-time-the-server-receives-a-request-b9c4f31bfbb3</a></p>
<p><a target="_blank" href="https://blog.gitguardian.com/authentication-and-authorization/">https://blog.gitguardian.com/authentication-and-authorization/</a></p>
<p><a target="_blank" href="https://medium.com/permify-tech-blog/jwt-vs-paseto-new-era-of-token-based-authentication-68b5ca6c3a32">https://medium.com/permify-tech-blog/jwt-vs-paseto-new-era-of-token-based-authentication-68b5ca6c3a32</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/jwt-dont-add-sensitive-information-into-json-webtoken-jwt-ac2c8e718dee">https://levelup.gitconnected.com/jwt-dont-add-sensitive-information-into-json-webtoken-jwt-ac2c8e718dee</a></p>
<p><a target="_blank" href="https://frontendinterviewquestions.medium.com/store-jwt-in-cookie-or-localstorage-7fa39fcc85b5">https://frontendinterviewquestions.medium.com/store-jwt-in-cookie-or-localstorage-7fa39fcc85b5</a></p>
<p><a target="_blank" href="https://medium.com/pharos-production/authentication-authorization-oauth-2-0-openid-connect-and-sso-part-2-b8eb8f51866b">https://medium.com/pharos-production/authentication-authorization-oauth-2-0-openid-connect-and-sso-part-2-b8eb8f51866b</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/the-complete-guide-to-oauth-2-0-and-openid-connect-protocols-35ebc1cbc11a">https://medium.com/better-programming/the-complete-guide-to-oauth-2-0-and-openid-connect-protocols-35ebc1cbc11a</a></p>
<p><a target="_blank" href="https://codebyumar.medium.com/5-common-mistakes-developers-make-with-api-authentication-38e9507d9389">https://codebyumar.medium.com/5-common-mistakes-developers-make-with-api-authentication-38e9507d9389</a></p>
]]></content:encoded></item><item><title><![CDATA[Front-end Security Hanbook]]></title><description><![CDATA[When it comes to security, front-end security is a crucial aspect of web development that is often overshadowed by its back-end counterpart. However, overlooking front-end security can leave your web applications vulnerable to a wide range of threats...]]></description><link>https://blog.tuanhadev.tech/front-end-security-hanbook</link><guid isPermaLink="true">https://blog.tuanhadev.tech/front-end-security-hanbook</guid><category><![CDATA[Security]]></category><category><![CDATA[securityawareness]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[attack]]></category><category><![CDATA[hacker]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Mon, 07 Apr 2025 12:31:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/mT7lXZPjk7U/upload/ed165ba059dabd2c1803e4e8eaf91915.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When it comes to <a target="_blank" href="https://www.griddynamics.com/solutions/enterprise-security">security</a>, front-end security is a crucial aspect of web development that is often overshadowed by its back-end counterpart. However, overlooking front-end security can leave your web applications vulnerable to a wide range of threats, including cross-site scripting (XSS) attacks, cross-site request forgery (CSRF) attacks, and other security vulnerabilities. This article will expose essential front-end security best practices to help you, the front-end developer, safeguard your web applications from malicious scripts and potential security risks.</p>
<h2 id="heading-understanding-the-front-end-security-landscape">Understanding the front-end security landscape</h2>
<p>Before delving into best practices, let’s establish a foundational understanding of front-end security and the associated terminology. Front-end security primarily deals with protecting the client-side of web applications, including the user interface and any Javascript code executed in the user’s browser. It focuses on mitigating security risks by implementing various security measures.</p>
<p>Maintaining a cybersecurity mindset in front-end development is crucial because it emphasizes the importance of proactive security measures. Front-end developers need to be vigilant in preventing common vulnerabilities like cross-site scripting (XSS) and ensuring data remains protected. It means following best practices, staying updated on threats, and thinking like a potential attacker to identify and fix vulnerabilities before they become problems. This mindset helps create secure web applications that prioritize user privacy and safety right from the start.</p>
<h2 id="heading-common-issues-with-front-end-security">Common Issues With Front-End Security</h2>
<p>There are countless issues that linked to Front-end security that could cause significant issues to the entire application. However, the following are some of the most prevalent problems that must be considered when considering Front-end security:</p>
<h3 id="heading-cross-site-scripting-xss">Cross-Site Scripting (XSS)</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743074085863/92708179-4485-4fee-a33a-aba5ec2e1c64.webp" alt class="image--center mx-auto" /></p>
<p>As web development evolves, the risk associated with protecting web applications is also increasing. One of the most significant and growing threats today is Cross-Site Scripting (XSS). The short form of Cross-site scripting is css, but this naming will conflict with Cascading Style Sheets (CSS). So, we call cross-site scripting as XSS.</p>
<p>XSS is a type of security vulnerability where attackers inject malicious scripts into web pages viewed by users. Since the malicious code is injected on the client side, the victims unknowingly execute the code, allowing attackers to bypass access controls and gain unauthorized access to sensitive information.</p>
<p>Improving protection against XSS is crucial in maintaining the security and integrity of web applications. Developers must implement robust security measures, such as input validation, output encoding, and using security-focused libraries, to mitigate the risks associated with CSS attacks.</p>
<p><strong>Understanding the Risks of XSS</strong></p>
<p>XSS attacks can have several consequences, including:</p>
<ul>
<li><p><strong>User data being compromised</strong>: Sensitive user information such as personal details, passwords, and financial data can be exposed to attackers.</p>
</li>
<li><p><strong>Stealing of cookies</strong>: Cookies, which are small pieces of data sent from a server to a web browser containing user information, can be stolen by attackers. This can lead to session hijacking and unauthorized access to user accounts.</p>
</li>
<li><p><strong>Unauthorized actions performed on behalf of the user</strong>: Attackers can perform actions such as making transactions, changing account settings, or sending messages without the user’s consent.</p>
</li>
<li><p><strong>Capturing the keystrokes of the user</strong>: By injecting malicious scrips, attackers can monitor and record user keystrokes, leading to the theft of sensitive information like passwords and credit card numbers.</p>
</li>
</ul>
<p><strong>Decoding XSS Attack Mechanisms</strong></p>
<p>DOM-based XSS is a common type of vulnerability where an attacker exploits the Document Object Model (DOM) to execute malicious script into the user’s browser. This occurs when client-side scripts directly manipulate the DOM, leading <code>to</code> unexpected execution of the injected scripts.</p>
<p>Consider the following example, where a web page uses Javascript to read the URL hash fragment and display it on the screen.</p>
<pre><code class="lang-javascript">&lt;!DOCTYPE html&gt;
<span class="xml"><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>DOM XSS Example<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>Welcome!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"hashElement "</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">script</span>&gt;</span><span class="javascript">
        <span class="hljs-comment">// Get the hash value from the URL</span>
        <span class="hljs-keyword">var</span> hash = <span class="hljs-built_in">window</span>.location.hash.substring(<span class="hljs-number">1</span>);

        <span class="hljs-comment">// Display the hash value in the " hashElement" </span>
        <span class="hljs-built_in">document</span>.getElementById(“hashElement”).innerHTML = <span class="hljs-string">"Hello, "</span> + hash + <span class="hljs-string">"!"</span>;
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</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></span>
</code></pre>
<p>In the above code snippet, the script retrieves the hash fragment from the URL and directly inserts it into the DOM. However, this approach is insecure. An attacker can exploit this by crafting a URL such as:</p>
<p><code>http://example.com/#&lt;script&gt;alert('XSS')&lt;/script&gt;</code></p>
<p>When a user visits a page with a URL containing a malicious hash fragment like the one above, the script executes immediately upon the page load. This vulnerability arises because the Javascript code uses innerHTML to insert the unsanitized hash fragment into the DOM.</p>
<p>If, instead, a simple alert, the injected script contains malicious code designed to steal sensitive information, the consequences could be severe. For example, an attacker could craft a URL like <code>http://example.com/#&lt;script&gt;stealCookies()&lt;/script&gt;</code>, where <code>stealCookies()</code> is a function that sends the user’s cookie to the attacker’s server, and then the user's sensitive information is compromised.</p>
<p><strong>Mitigation Strategy for XSS Vulnerabilities</strong></p>
<p>This kind of attack can be prevented if the user input is sanitized and validated before it’s inserted into the DOM.</p>
<ul>
<li>Prefer using APIs that inherently do not interpret HTML, such as <code>textContent</code>instead of <code>innerHtml</code>.</li>
</ul>
<p><code>document.getElementById('hashElement').textContent = "Hello, " + hash + "!"</code>;</p>
<ul>
<li>Sanitize Input: Use libraries like DOMPurify to clean user input before inserting it into the DOM.</li>
</ul>
<p><code>var cleanHash = DOMPurify.sanitize(hash);</code><br /><code>document.getElementById('hashElement').innerHTML = "Hello, " + cleanHash + "!";</code></p>
<p><strong>React’s Approach to Mitigating XSS Vulnerabilities</strong></p>
<p>React, a popular Javascript library for building user interfaces, has built-in mechanisms to help prevent DOM-based XSS attacks.</p>
<p>React will automatically escape all the content that is embedded inside the JSX, so that it will treat the content inside JSX as a plain instead of HTML thereby preventing the insertion of any external scripts.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SampleComponent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  render() {
    <span class="hljs-comment">// Assume the hash value comes from the URL and is passed as a prop</span>
    <span class="hljs-keyword">const</span> { hash } = <span class="hljs-built_in">this</span>.props;

    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome!<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>Hello, {hash}!<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>
    );
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SampleComponent;
</code></pre>
<p>In the above example, even if the hash variable contains the script tag, React will escape it and render it as a string and not as executable code.</p>
<p><strong>Using</strong> <code>dangerouslySetInnerHtml</code></p>
<p>React offers the <code>dangerouslySetInnerHtml</code> attribute as a method to directly inject HTML into the DOM. However, it should be used cautiously, and only you can guarantee the content is safe and thoroughly sanitized.</p>
<p>If you encounter unavoidable scenarios where using the <code>dangerouslySetInnerHtml</code> attribute is necessary, always ensure that the input is sanitized rigorously with a trusted library like DOMPurify. This step helps remove any potentially harmful code, thereby mitigating the risk of XSS vulnerabilities.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> DOMPurify <span class="hljs-keyword">from</span> <span class="hljs-string">'dompurify'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">XSSComponent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  render() {
    <span class="hljs-keyword">const</span> { hash } = <span class="hljs-built_in">this</span>.props;
    <span class="hljs-keyword">const</span> sanitizedHash = DOMPurify.sanitize(hash);

    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">dangerouslySetInnerHTML</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">__html:</span> `<span class="hljs-attr">Hello</span>, ${<span class="hljs-attr">sanitizedHash</span>}!` }} /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> XSSComponent;
</code></pre>
<h3 id="heading-cross-site-request-forgery-csrf">Cross-Site Request Forgery (CSRF)</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742992924584/47666736-e63c-4590-8556-5a99dcace9a5.webp" alt class="image--center mx-auto" /></p>
<p>Cross-site request forgery (also known as CSRF) is a web security vulnerability that allows an attacker to introduce users to perform actions that they do not intend to perform. It allows an attacker to partly circumvent the same-origin policy, which is designed to prevent different websites from interfering with each other.</p>
<p>For example, Chris might be logged into his online banking while checking his email. In the meanwhile, he might click on a link in the phishing email with a transfer request (such as a deceptively short link) asking Chris’s bank to transfer money to the compromised bank account. Since Chris is logged into his bank account, the transfer request will be executed automatically because it is made through a browser authorised by Chris.</p>
<p>To prevent the CSRF in your web application, this is the step we should follow:</p>
<ol>
<li><strong>Store the token under HttpOnly with sam-site Cookie Attribute</strong></li>
</ol>
<p>Generally, we don’t save the user token inside local storage or redux. So far, the suggestion that I have found is to save the cookie inside HttpOnly cookies with strict same-site configuration. Well, the HttpOnly cookies mean that the token can not be loaded on the client-side; it is a tag added to the browser cookie that prevents client-side scripts from accessing data. It provides a gate that prevents the specialized cookie from being accessed by anything other than the server. Nextjs would be a good way to achieve this solution because it has an express backend server as a developer that is able to save tokens inside HttpOnly cookies. Besides that, the cookies should be set to <code>strict</code> because the browser will not include the cookie in any requests that originate from another site. This is the most defensive option, but it can impair the user experience because if a logged-in user follows a third-party link to a site, then they will appear not to be logged in and will need to log in again before interacting with the site in the normal way.</p>
<p>Reference link: <a target="_blank" href="https://portswigger.net/web-security/csrf/samesite-cookies">https://portswigger.net/web-security/csrf/samesite-cookies</a></p>
<ol start="2">
<li><strong>Follow REST principles</strong></li>
</ol>
<p>It is very dangerous if we use this <code>GET</code> method to change the state of the server. For example, If Chris is accessing the bank websites, and the bank website uses a GET request to transfer funds as example below - <code>GET &lt;http://bank.com/transfer.do?name=Chris&amp;amount=10&gt; HTTP/1.1</code> This is very dangerous if the attacker tamper with the query strings and make a link into an image or a script and send it to the user via an unsolicited email with HTML content, then Chris’s bank account will automating executed that query while they are doing the online banking. The attackers can even put the script such as <code>&lt;img src="&lt;http://bank.com/transfer?name=Chris&amp;amount=10&gt;" width="0" height="0" border="0"&gt;</code> . Other methods such as <code>Create</code> , <code>Update</code> , <code>Delete</code> have the same issue with <code>GET</code> method. So the best way to prevent as a developer is to follow REST principles as they are provided.</p>
<ol start="3">
<li><strong>Implement Anti-CSRF tokens</strong></li>
</ol>
<p>Anti-CSRF tokens are to provide the user browser with a piece of information and check if the web browser will send it back. The token must be unique and provided by the third party. After that, the back end of the web application will not proceed unless it verifies the <a target="_blank" href="http://token.so/">token</a>. In this way, only the user can send requests within an authenticated session. Below is an example:</p>
<pre><code class="lang-javascript">&lt;Form&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"name"</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"token"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"unique_value"</span> /&gt;</span></span>
&lt;/Form&gt;
</code></pre>
<p>If the attacker performs a CSRF using a malicious site, it will be hard to know the current token that is set inside the cookies. The backend server won’t process the request without that token in order to make a protection from CSRF attacks. More references can read this:</p>
<p>Reference link: <a target="_blank" href="https://www.invicti.com/blog/web-security/protecting-website-using-anti-csrf-token/">Protect your website with anti-CSRF tokens | Invicti</a></p>
<h3 id="heading-injection-attack">Injection Attack</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743074188952/ce73bf2c-c168-4d5b-aa9c-6ec8fb399f6c.webp" alt class="image--center mx-auto" /></p>
<p>As the name implies, injection attacks or vulnerabilities allow an attacker to inject malicious code or commands into the application’s input fields, exploiting vulnerabilities in data processing mechanisms.</p>
<p>This is one of the most common forms of vulnerability that can be present in an application and has also been added to the <a target="_blank" href="https://owasp.org/Top10/A03_2021-Injection/">OSWAP Top 10</a> list of vulnerabilities.</p>
<p>Even though there can be several injection attacks, such as SQL, Command, or even XPath injections, the principle behind the vulnerability remains the same.</p>
<p>Some of the most common causes for the injection vulnerabilities include:</p>
<ul>
<li><p>Lack of input validation: Failure to properly verify and sanitize user input before processing allows attackers to introduce harmful payloads into application input fields.</p>
</li>
<li><p>Dynamic Query Construction: Applications that dynamically generate SQL queries, shell commands, or XPath expressions from user inputs are particularly vulnerable to injection attacks.</p>
</li>
<li><p>Insufficient Escaping: Insecure handling of special characters or inability to escape the user input before combining it into queries or instructions opens programs to injection attacks.</p>
</li>
</ul>
<p><strong>How can you prevent Injection Attacks?</strong></p>
<p>Preventing an injection attack is a two-part strategy:</p>
<ol>
<li><p>First, you need to ensure that your Front-end input fields are rightfully validated and sanitized. You need to prevent users from inserting malicious code into your fields.</p>
</li>
<li><p>After you have validated your front end, it’s also important to sanitize the payloads you receive on your backend. Don’t trust your payloads that anyone can get your API endpoints and start sending malicious input. So, ensure that you sanitize your back-end payloads as well. Additionally, utilize tools like <a target="_blank" href="https://portswigger.net/burp/documentation/scanner">Burp Scanner</a>, <a target="_blank" href="https://sqlmap.org/">sqlmap</a>, <a target="_blank" href="https://github.com/ron190/jsql-injection">jSQL Injection,</a> and <a target="_blank" href="https://www.invicti.com/">Invicti</a> to detect potential SQL attacks and related vulnerabilities in your applications.</p>
</li>
</ol>
<h3 id="heading-man-in-the-middle-attack">Man-in-the-Middle Attack</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743076168417/8deec680-21d6-4c83-ab2f-1764ae1b5561.webp" alt class="image--center mx-auto" /></p>
<p>Man-in-the-middle (MitM) Attacks force an attacker to intercept and manipulate the information that is being transmitted between two parties.</p>
<p>For example, attackers can intercept your connection to Facbook.com and steal your credentials and forward you back to Facebook.</p>
<p>These attacks occur when an attacker exploits an insecure communication channel (often through public wifi). A victim of this attack doesn’t feel that they are being attacked as they assume they are holding a perfectly normal and secure conversation with the server when the information they are sharing is being spied upon or altered along the way.</p>
<p><strong>How can you prevent a Man-in-the-middle attack?</strong></p>
<ul>
<li><p>Use a secure internet connection and log out of apps you no longer use.</p>
</li>
<li><p>Don’t connect to networks you don’t know. For example, don’t connect to a free Wifi that is available in your coffee.</p>
</li>
<li><p>Use secure communication protocols such as HTTPS and TLS to encrypt all data in transit.</p>
</li>
</ul>
<h3 id="heading-clickjacking">Clickjacking</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743076868564/fcf02ac0-e81d-4882-8f3e-a50327d99c8b.webp" alt class="image--center mx-auto" /></p>
<p>Clickjacking, also known as UI redressing, is a type of attack where malicious actors tricks users into clicking on something different from what they perceive by embedding web pages within iframes. This can lead to unauthorized actions and compromise user security.</p>
<p>Clickjacking involves placing a transparent or opaque over a legitimate webpage element, causing users to unknowingly perform actions such as changing settings or transferring funds.</p>
<p>Consider a scenario where an attacker embeds a hidden iframe from a banking site into a trusted webpage. When a user clicks on a seemingly harmless button, they might actually be authorizing a bank transaction.</p>
<p>Here’s an example of a vulnerable page:</p>
<pre><code class="lang-xml"><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>Clickjacking Example<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>Welcome to Our Site<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"alert('Clicked!')"</span>&gt;</span>Click Me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">iframe</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://example-bank.com/transfer"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"opacity:0; position:absolute; top:0; left:0; width:100%; height:100%;"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">iframe</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><strong>Preventing Clickjacking with Javascript</strong></p>
<p>To prevent clickjacking attacks, you can use JavaScript to ensure that your website is not being framed. Here’s a step-by-step guide on how to implement this protection:</p>
<ol>
<li><strong>Javascript Fram Busting</strong></li>
</ol>
<p>Frame busting involves using JavaScript to detect if your website is loaded inside an iframe and breaking out of it.</p>
<pre><code class="lang-xml"><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>Frame Busting Example<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.top !== <span class="hljs-built_in">window</span>.self) {
            <span class="hljs-built_in">window</span>.top.location = <span class="hljs-built_in">window</span>.self.location;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</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>Secure Site<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 site is protected from clickjacking attacks.<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>In this example, the JavaScript checks if the current window (window.self) is not the topmost window (window.top). If it's not, it redirects the topmost window to the current window's URL, effectively breaking out of the iframe.</p>
<ol start="2">
<li><strong>Enhanced Frame Busting with Event Listeners</strong></li>
</ol>
<p>You can further enhance your frame-busting technique by using event listeners to continuously check if your page is framed.</p>
<pre><code class="lang-xml"><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>Enhanced Frame Busting<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">preventClickjacking</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.top !== <span class="hljs-built_in">window</span>.self) {
                <span class="hljs-built_in">window</span>.top.location = <span class="hljs-built_in">window</span>.self.location;
            }
        }

        <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'DOMContentLoaded'</span>, preventClickjacking);
        <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'load'</span>, preventClickjacking);
        <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'resize'</span>, preventClickjacking);
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</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>Secure Site<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 site is protected from clickjacking attacks.<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>In this example, the preventClickjacking function is called on the DOMContentLoaded, load, and resize events to ensure continuous protection.</p>
<p><strong>Server-Side Protection</strong></p>
<p>While JavaScript methods are useful, implementing server-side protection provides an additional layer of security. Here’s how to set up HTTP headers in Apache and Nginx to prevent clickjacking:</p>
<ol>
<li><strong>X-Frame-Options Header</strong></li>
</ol>
<p>The X-Frame-Options header allows you to specify whether your site can be embedded in iframes. There are three options:</p>
<p>DENY: Prevents any domain from embedding your page.<br />SAMEORIGIN: Allows embedding only from the same origin.<br />ALLOW-FROM uri: Allows embedding from the specified URI.<br />Example:</p>
<pre><code class="lang-xml">X-Frame-Options: DENY
</code></pre>
<p>Apache Configuration<br />Add this header to your server configuration:</p>
<pre><code class="lang-xml"># Apache
Header always set X-Frame-Options "DENY"
</code></pre>
<p>Nginx Configuration<br />Add this header to your server configuration:</p>
<ol start="2">
<li><strong>Content-Security-Policy (CSP) Frame Ancestors</strong></li>
</ol>
<p>CSP provides a more flexible approach through the frame-ancestors directive, which specifies valid parents that may embed the page using iframes.</p>
<p>Example:</p>
<pre><code class="lang-xml">Content-Security-Policy: frame-ancestors 'self'
</code></pre>
<p>Apache Configuration<br />Add this header to your server configuration:</p>
<p>Example:</p>
<pre><code class="lang-xml"># Apache
Header always set Content-Security-Policy "frame-ancestors 'self'"
</code></pre>
<p>Nginx Configuration<br />Add this header to your server configuration:</p>
<pre><code class="lang-xml"># Nginx
add_header Content-Security-Policy "frame-ancestors 'self'";
</code></pre>
<h3 id="heading-insecure-direct-object-reference-idor">Insecure Direct Object Reference (IDOR)</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743426248371/61c4a49d-6116-4d2e-945c-a17508bf09d5.webp" alt class="image--center mx-auto" /></p>
<p>This type of vulnerability occurs when the application exposes the internal object references in a predictable or unauthenticated manner, allowing attackers to manipulate these references to gain unauthorized access to sensitive data or resources.</p>
<p>IDOR works when internal object references, such as database keys or file paths, are directly exposed to users without proper authorization checks. This way, attackers can access these resources by guessing or incrementing values to access these resources.</p>
<p>Common causes of IDOR vulnerability include:</p>
<ol>
<li><p><strong>Lack of Access Controls</strong>: Failure to implement sufficient access controls or permission procedures allows users to access internal object references without suitable validation directly.</p>
</li>
<li><p><strong>Predictable Object References</strong>: Applications with predictable or sequential object references, such as sequential database keys or predictable file paths, are more vulnerable to IDOR attacks.</p>
</li>
<li><p><strong>Insecure Direct Links</strong>: Direct links or URLs that expose internal object references without adequate authentication or authorization might result in IDOR vulnerabilities.</p>
</li>
</ol>
<h3 id="heading-insecure-authentication-and-session-management">Insecure Authentication and Session Management</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743493231321/9e4d5767-2165-4320-ab15-f0d1058cd8a1.webp" alt class="image--center mx-auto" /></p>
<p>These vulnerabilities allow attacks to bypass or masquerade valid sessions and users into gaining unauthorized access to sensitive resources.</p>
<p>This type of vulnerability has been persistent for a long time and has also been mentioned within the <a target="_blank" href="https://owasp.org/Top10/A01_2021-Broken_Access_Control/">OWASP Top 10 list</a> of vulnerabilities and on the <a target="_blank" href="https://owasp.org/API-Security/editions/2023/en/0xa2-broken-authentication/">OWASP Top 10 for APIs</a>.</p>
<p>Some common causes for these vulnerabilities include:</p>
<ul>
<li><p><strong>Session Fixation</strong>: Improper management of session IDs, such as failing to regenerate session tokens after authentication or utilizing predictable session identifiers, can expose the application to session fixation attacks. Attackers can take over user sessions by altering or guessing session tokens.</p>
</li>
<li><p><strong>Persistent Cookies</strong>: Persistent cookies without expiration dates or long periods raise the possibility of unauthorized access and account compromise. Attackers can steal the persistent session cookie saved on users’ devices and exploit it to get continued access to their accounts.</p>
</li>
<li><p><strong>Insufficient Account Lock Mechanisms</strong>: A lack of account logout methods and insufficient rate limits on login attempts might make user accounts vulnerable to brute-force assaults. Attackers can keep guessing passwords until they gain unauthorized access to user accounts.</p>
</li>
</ul>
<h3 id="heading-thrid-party-component-risks">Thrid-Party Component Risks</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743494627729/99fabd62-a274-4efc-b121-36501e2cc6ad.webp" alt class="image--center mx-auto" /></p>
<p>Almost all modern-day applications use third-party components such as libraries, frameworks, plugins, and APIs to accelerate development and enhance functionality. Even though these components have their benefits, they can also introduce inherent security risks that could jeopardize the application’s security and integrity.</p>
<p>Some of the most common risks brought in by third-party components are:</p>
<ol>
<li><p><strong>Security Vulnerabilities:</strong> Third-party components may have security flaws or authentication bypasses that attackers might use to compromise your application.</p>
</li>
<li><p><strong>Outdated or Unsupported Versions</strong>: Using obsolete or unsupported versions of third-party components increases the risk of security vulnerabilities, as patches and updates that address known vulnerabilities may not be applied.</p>
</li>
<li><p><strong>Supply Chain Attacks</strong>: Attackers may compromise the software supply chain by injecting malicious code or backdoors into third-party components, resulting in widespread security breaches or data exfiltration.</p>
</li>
</ol>
<h3 id="heading-malicious-file-upload">Malicious File Upload</h3>
<p>File uploads could be risky when the developer doesn’t restrict the file upload. The attacks could be to the backend infrastructures and users. Let’s say the uploaded file contains malware, which can leverage the vulnerability on the server side. The file could be used to gain control of the server. Back-end developers should restrict and scan the file uploading. But in the front end, we could try to optimize it to prevent malicious file uploads. We are unable to scan the file on the server. However, we can run some validations from the recommendations below.</p>
<ul>
<li><p>only allows file extensions that your application requires</p>
</li>
<li><p>If the file extensions are valid, then check the type of the file. e.g, application/text, application/csv, etc.</p>
</li>
<li><p>Upload should be done over the secure channel (SSL)</p>
</li>
<li><p>You can get an antivirus/malware detector in your hosting services.</p>
</li>
<li><p>Proper permissions to the folder when you move new files.</p>
</li>
<li><p>Confirm that the file names are standard and without any special characters / Randomize upload file names.</p>
</li>
<li><p>Set a maximum name length and maximum file size.</p>
</li>
</ul>
<p>Reference Link: <a target="_blank" href="https://stackoverflow.com/questions/55591385/front-end-antivirus-scan-file-uploads">Front-end Untivirus Scan File Uploads</a></p>
<h3 id="heading-denial-of-service-dos">Denial of Service (DoS)</h3>
<p>Think of a busy road suddenly blocked by hundreds of cars, making it impossible for anyone to get through. That’s what a Denial of Service (DoS) attack does in the digital world. It clogs up websites or online services, so they become inaccessible to users.</p>
<p>In a DoS attack, cyber troublemakers flood a website or a service with an overwhelming amount of traffic or data. It’s like sending so many cars onto a road that it becomes jammed. When this happens, the website or service can’t handle all the requests, and it crashes or slows down significantly.</p>
<p>These attacks can be launched for several reasons. Sometimes, it’s to cause chaos and disrupt a service, but other times, it’s a distraction while cybercriminals carry out other attacks.</p>
<p>To protect against DoS attacks, website owners and service providers use specialized software and hardware to filter out malicious traffic. They also have backup systems to keep services running even if there is an attack.</p>
<p>As a user, you might experience a website's response slowly during a DoS attack, but there’s not much you can do to prevent it. Just like dealing with traffic jams on the road, patience is key when facing a DoS attack online.</p>
<h3 id="heading-distributed-denial-of-service-ddos">Distributed Denial of Service (DDoS)</h3>
<p>Imagine your favorite online game or a popular shopping website suddenly becoming so crowded that it crashes, and you can’t access it. That is what a Distributed Denial of Service (DDoS)attack does - it creates a digital stampede that overwhelms and paralyzes websites and online services.</p>
<p>In a DDoS attack, instead of one troublemaker, there are many. These cyber attackers gather a network of hijacked computers and devices, often called a “botnet“. It’s like an enemy of digital zombies that follows the hacker’s orders.</p>
<p>When the attack begins, the botnet floods the target website or service with a massive amount of fake traffic. It’s like thousands of people trying to get into a tiny shop at once. The target gets so swamped that it can’t handle all the requests, and it slows down or crashes.</p>
<p>DDoS attacks can be used for several reasons, from causing chaos and distracting from security teams while another cyber-attack is underway.</p>
<p>To protect against DDoS attacks, websites and service providers invest in strong cybersecurity infrastructure and monitoring systems to detect and mitigate the attack traffic.</p>
<p>As users, there is not much you can do to prevent a DDoS attack, but you can be patient and wait for the storm to pass. Just like waiting for a crowd event to calm down, staying calm during a DDoS attack is key to getting back online.</p>
<h2 id="heading-front-end-security-best-practices">Front-end security best practices</h2>
<p>Now that we have a clear picture of the threats, let’s explore some best practices to fortify your Front-end security.</p>
<h3 id="heading-cors-finally-explained">CORS Finally Explained</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743324952010/6f78bf11-0b65-4285-89de-f77c67106122.webp" alt class="image--center mx-auto" /></p>
<p>Seen the above before? Probably… and probably quite a lot…</p>
<p>There are millions of articles explaining how to fix the error above, but what exactly is this “Cross-Origin Resource Sharing“ thing, and why does it even exist?</p>
<p>Imagine this: you log into <code>bank.com</code>, which is your banking service. After logging in, a “session cookie is stored in your browser“. (Session cookies basically tell the server behind <code>bank.com</code> that your browser is now logged into your account.) All feature requests to <code>bank.com</code> will now contain this cookie, and it can respond properly, knowing you are logged in. Ok, so now you decide to check your mailbox. You receive a suspicious email, and of course, you choose to click on the link inside, which sends you to <code>attack.com</code>. Next, this website sends a request to <code>bank.com</code> to get your banking details. Keep in mind that <code>bank.com</code> still thinks that you are still logged in because of that session cookie…that cookie is stored in your browser. For the server behinds <code>bank.com</code>, it just looks like you requested your banking details normally, so it sends them back. Now, <code>attack.com</code> has access to these and store them elsewhere maliciously.</p>
<p>People realized this was bad, so browsers adopted an SOP (Same-Origin Policy) where if your browser notices that you are trying to make requests to <code>bank.com</code> <em>from anywhere other than</em> <code>bank.com</code> they will be blocked. Now, this is a key thing to realize - <strong>this is a browser-based policy</strong>. <code>bank.com</code> really has no way to tell where a request comes from, so it can’t protect much against attacks like CSRF. The browser you are using steps in and basically says that if you seem to be trying to request details for an origin (scheme + domain name + port, https//foo.com:4000, http//bar.org:3000, etc… Basically the URL), it will only send those requests for same origins.</p>
<p>Now, this was great at all, but it was incredibly limiting. I mean, public APIs won’t work at all. You couldn’t request data from the unless you used some sort of proxy solution.</p>
<p><strong>CSRF</strong></p>
<p>Here’s a thing: a server can sorta tell where a request came from. There is an “Origin“ header, which requests should have, showcasing what origin made a request. For instance, in the above example, the request would look something like this:</p>
<pre><code class="lang-xml">Request to -----&gt; bank.com
{
  Headers: { Origin: http://attack.com }
}
</code></pre>
<p><code>bank.com</code> in theory, should be checking this to make sure it only responds to requests where the origin makes sense. And it usually does, so SOP seems kinda limiting.</p>
<p>This is where CORS comes in.</p>
<p><strong>CORS</strong></p>
<p>When a web application from <code>example.com</code> attempts to request resources from <code>bank.com</code>, the browser automatically includes an <code>Origin</code> header in the request, indicating where the request originates from (<code>example.com</code>). Here's the crucial part: Instead of outright blocking such cross-origin requests under the SOP, <code>bank.com</code>'s server can inspect this <code>Origin</code> header and decide whether to allow or deny the request based on its own CORS policy.</p>
<p>If <code>bank.com</code> considers <code>example.com</code> trustworthy or the resource being requested is meant to be publicly accessible, it can respond with specific CORS headers, such as <code>Access-Control-Allow-Origin</code>, indicating which origins are permitted to access the resource. This header might be set to <code>http://example.com</code>, explicitly allowing this origin, or <code>*</code> for public resources that any origin can access.</p>
<p>Of course, the browser facilitates all this. If any of it is wrong, you will get that nasty error.</p>
<p>Now, what if the request doesn’t have the origin header? What if it has a bunch of other headers and doesn't use one of the basic HTTP methods?</p>
<p>In these situations, the handling of CORS becomes a bit more intricate as it is no longer a “simple request“. This is where the concept of “preflight” requests in CORS comes into play.</p>
<p><strong>Preflight</strong></p>
<p>For certain types of requests that could potentially modify data on the server — Those are use HTTP methods like PUT, DELETE, or use headers that are not automatically included in every requests — browsers will first send a “prefight“ request before making the actual request. This preflight request is an HTTP OPTIONS request, and its purpose is to check with the server whether the actual request is safe to send.</p>
<p>The preflight request includes headers that describe the HTTP method and headers of the actual request. Here’s what happens next:</p>
<ol>
<li><p>Server Response: If the server supports the CORS policy and the actual request, it responds to the preflight request with headers indicating what methods and headers are allowed. This might include headers like <code>ccess-Control-Allow-Methods</code> and <code>Access-Control-Allow-Headers</code>.</p>
</li>
<li><p>Browser Decision: Based on the server’s response to the preflight request, the browser decides whether to proceed with the actual request. If the server’s response indicates that the request is allowed, the browser sends it; if not, the browser blocks the request, and you will see an error related to CORS.</p>
</li>
</ol>
<h3 id="heading-content-security-policies">Content Security Policies</h3>
<p>Content Security Policy (<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/CSP">CSP</a>) is an added layer of security that helps to reduce and mitigate certain types of attacks, including cross-site scripting (<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/XSS">XSS</a>) and data injection attacks. These attacks are used for everything from data theft to site defacement to distribution of malware.</p>
<p>As the name suggests, CSP is a set of instructions you can send with your Javascript code to the browser to control its execution. For example, you can set up a CSP to restrict the execution of Javascript to a set of whitelisted domains and ignore any inline scripts and event handlers to protect from XSS attacks. In addition, you can specify that all the scripts should load via HTTPS to reduce the risk of packet sniffing attacks.</p>
<p>So how should I configure a CSP for web applications?</p>
<p>There are two ways to configure a CSP. One approach is to return a specific HTTP Header <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy"><code>Content-Security-Policy</code></a>. The other is to specify the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta">&lt;meta&gt;</a> element in your HTML page.</p>
<p>Recommended to read this article:</p>
<p><a target="_blank" href="https://www.stackhawk.com/blog/react-content-security-policy-guide-what-it-is-and-how-to-enable-it/">https://www.stackhawk.com/blog/react-content-security-policy-guide-what-it-is-and-how-to-enable-it/</a></p>
<p>Other than that, NextJs is also able to improve security by setting the <code>headers</code> in <code>next.config.js</code> . More information - <a target="_blank" href="https://nextjs.org/docs/advanced-features/security-headers">Advanced Features: Security Headers | Next.js</a></p>
<p><strong>Let’s look at a Sample CSP</strong></p>
<p><a target="_blank" href="https://nextjs.org/docs/advanced-features/security-headers">Assume that you</a> <a target="_blank" href="https://www.stackhawk.com/blog/react-content-security-policy-guide-what-it-is-and-how-to-enable-it/#:~:text=You">set the following <code>Content-Security-Policy</code> for your we</a>b application:</p>
<pre><code class="lang-xml">Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com;
</code></pre>
<p>Then, this will allow loading Javascript like from <code>https://example.com/js/*</code> but will block <code>https://someotherexample.com/js/*</code> by the browser as specified in the CSP. Furthermore, any Inline Scripts are also blocked by default unless you use hashes and nonces to allow them to execute.</p>
<p>If you haven’t heard of hashes and nonces, I would highly recommend referring to <a target="_blank" href="https://content-security-policy.com/examples/allow-inline-script/">this example link</a> to realize its true potential.</p>
<p>In a nutshell, with the hash operation, you can specify the hash of the Javascript file as an attribute to the script block where the browser will first validate the hash before executing it.</p>
<p>The same goes for the nonce, where we can generate a random number and specify it at the CSP header while referring to the same nonce at the Script block.</p>
<p><strong>How do you know if there are any CSP Violations?</strong></p>
<p>The beauty of CSP is that it has covered the scenario of reporting the violations back to you. As a part of CSP, you can define a URL where the user’s browser will automatically send a violation report back to your server for further analysis.</p>
<p>For this, you need to set up an endpoint that handles the POST payloads sent as the CSP violation report by the browser. The following shows an example of specifying a <code>/csp-incident-reports</code> path to receive a violation report payload.</p>
<p><code>Content-Security-Policy: default-src 'self'; report-uri /csp-incident-reports</code></p>
<p>If we include a Javascript or Style outside the site’s own origin (e.g, otherdomain.com), let’s say by accident when we visit a site URL (e.g, example.com), the above policy will reject it from loading to the browser and submit the following violation report as the HTTP POST payload.</p>
<pre><code class="lang-xml">{
  "csp-report": {
    "document-uri": "http://example.com/index.html",
    "referrer": "",
    "blocked-uri": "http://otherdomain.com/css/style.css",
    "violated-directive": "default-src 'self'",
    "original-policy": "default-src 'self'; report-uri /csp-incident-reports"
  }
}
</code></pre>
<p><strong>Browser Support and Tools</strong></p>
<p>As you can see, all the major browsers support the CSP feature. This is good news since the investment we put in creating the CSP addresses a larger user base.</p>
<p>Besides, browsers like Chrome have gone even further by providing tools to validate CSP attributes. For example, if you define the hash of the Javascript, the Chrome Developer Console will promote the correct hash for developers to rectify any errors.</p>
<p>In addition, if you use Webpack to bundle your Javascripts, you can find a webpack plugin named <a target="_blank" href="https://www.npmjs.com/package/csp-html-webpack-plugin">CSP HTML WebPack Plugin</a> to append the hash at build time and automate this process.</p>
<h3 id="heading-avoid-iframes-if-possible">Avoid Iframes if possible</h3>
<p>Iframe is a simple content embedding technique used in web development. However, using iframes would come with security risks. Through IFrame, attackers are able to inject malicious executables or viruses into our web application and execute them on the user’s browser. More information can be read <a target="_blank" href="https://blog.bitsrc.io/4-security-concerns-with-iframes-every-web-developer-should-know-24c73e6a33e4#:~:text=iframes%20use%20multiple%20tags%20to,execute%20them%20in%20user's%20devices">this</a>:</p>
<h3 id="heading-strict-user-input-the-first-point-of-attack">Strict User Input (the First Point of Attack)</h3>
<p>User Input should always be strict in nature to avoid vulnerabilities such as SQL injection, clickjacking, etc. So it’s important to validate or sanitize user input before sending it to the back end.</p>
<p>Sanitizing data can be done by removing or replacing contextually dangerous characters, such as by using a whitelist and escaping the input data.</p>
<p>However, I realize that sanitizing and encoding is not an easy task for all existing possibilities, so we may use the following open-source libraries:</p>
<ul>
<li><p><a target="_blank" href="https://www.npmjs.com/package/dompurify"><code>DOMPurify</code></a>: This is the most simple to use and has one method to sanitize the user’s input. It has an option to customize the rules, and it supports HTML5, SVG, and MathML.</p>
</li>
<li><p><a target="_blank" href="https://www.npmjs.com/package/secure-filters"><code>secure-filters</code></a>: A Salesforce library that provides methods to sanitize HTML, Javascript, Inline CSS styles, and other contexts. It’s especially useful when you want to make use of user input in other places, for example, generating CSS or Javascript.</p>
</li>
</ul>
<p>In the case of file upload, always check the file type, use a file filter function, and allow only certain file types to get uploaded. Refer to <a target="_blank" href="https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload">this</a> for more.</p>
<h3 id="heading-beware-of-hidden-fields-or-data-stored-in-browser-mermory">Beware of Hidden Fields or Data Stored in Browser Mermory</h3>
<p>If we add <code>input=”hidden”</code> to hide the sensitive data in the page or add them in the browser <code>localStorage</code>, <code>sessionStorage</code>, <code>cookies</code> and think that is safe, we need to think again.</p>
<p>Everything is added to the browser and can be accessed by attackers easily. An attacker can open the dev tools and change all the in-memory variables. And what if you had hidden the auth page upon the <code>localStorage</code>, <code>sessionStorage</code>, and <code>cookies</code> values?</p>
<p>There are tools like <a target="_blank" href="https://www.zaproxy.org/">ZapProxy</a> and even inspection tools in the browser that can expose those values to attackers if they find a way to inject a script, and they can use them to attack further.</p>
<p>Hence avoid using <code>type="hidden"</code> and avoid storing keys, auth tokens, etc, in the browser's in-memory storage as much as possible.</p>
<h3 id="heading-enable-xss-protection-mode">Enable XSS Protection Mode</h3>
<p>If somehow an attacker injects the malicious code from the user input, we can instruct the browser to block the response by supplying the <code>"X-XSS-Protection": "1; mode=block"</code> header.</p>
<p>Most modern browsers have XSS protection mode enabled by default but it’s still recommended to include the <code>X-XSS-Protection</code> header. This helps to ensure better security for older browsers that don’t support CSP headers.</p>
<h3 id="heading-avoid-typical-xss-mistakes">Avoid Typical XSS Mistakes</h3>
<p>An XSS attack is usually traced to the DOM API’s innerHTML. For instance:</p>
<p><code>document.querySelector('.tagline').innerHTML = nameFromQueryString</code></p>
<p>Any attacker is able to inject malicious code with the line above:</p>
<p>Consider using <code>textContent</code> instead of <code>innerHTML</code> to prevent generating HTML output altogether. If you don’t generate HTML, there is no way to insert Javascript. You may see the content, but nothing will happen.</p>
<p>Keep an eye out for a new <a target="_blank" href="https://developers.google.com/web/updates/2019/02/trusted-types">Trusted Types specification</a>, which aims to prevent all DOM-based cross-site scripting attacks made by goodgler.</p>
<p>In the case of react.js, <code>dangerouslySetInnerHTML</code> is unambiguous and cautionary and can have a similar impact as <code>innerHTML</code>.</p>
<p><em>Note: Don't Set the</em> <code>innerHTML</code> <em>value-based on user input and use textContent instead of</em> <code>innerHTML</code> <em>as much as possible.</em></p>
<p>Also, HTTP response headers <code>Content-Type</code> and <code>X-Content-Type-Options</code> should be set properly, with their intended behavior. For example, JSON data should never be encoded as text/HTML to prevent accidental execution.</p>
<h3 id="heading-keep-errors-generic">Keep Errors Generic</h3>
<p>An error like “Your password is incorrect“, may be helpful to the users but also to the attackers. They may figure out information from these errors that helps them to plan their next action.</p>
<p>When dealing with accounts, emails, and PII, we should try to use ambiguous errors like “Incorrect login information.“</p>
<h3 id="heading-use-captcha">Use Captcha</h3>
<p>Using Captcha at public-facing endpoints (login, registration, contact). A Captcha is a computer program or system intended to distinguish humans from bots and can help stop DoS (Denial of Service) attacks.</p>
<h3 id="heading-always-set-referer-policy">Always Set <code>Referer-Policy</code></h3>
<p>Whenever we use an anchor tag or a link that navigates away from the website, make sure you use a header policy <code>"Referrer-Policy": "no-referrer"</code> or, in case of the anchor tag, set <code>rel = noopener or noreferrer</code>.</p>
<p>When we don’t set these headers and rel, the destination website can obtain data like session tokens and database IDs.</p>
<h3 id="heading-audit-dependencies-regularly">Audit Dependencies Regularly</h3>
<p>Run <code>npm audit</code> regularly to get a list of vulnerable packages and upgrade them to avoid security issues.</p>
<p>Github now flags vulnerable dependencies. We can also use <a target="_blank" href="https://snyk.io/">Synk</a>, which checks your source code automatically and opens pull requests to bump versions.</p>
<h3 id="heading-carefully-consider-autofill-fields">Carefully Consider Autofill Fields</h3>
<p>Personal identification information stored in the autofill of a browser can be convenient for both users and attackers.</p>
<p>Attackers add third-party scripts to exploit browsers’s built-in autofill to extract email addresses for building tracking identifiers. They can use these to build user browsing history profiles, which they can sell to the bad guys. Read more on <a target="_blank" href="https://freedom-to-tinker.com/2017/12/27/no-boundaries-for-user-identities-web-trackers-exploit-browser-login-managers/">this</a>.</p>
<p>Many of us aren’t even aware of what information our browser’s autofill has stored.</p>
<p><em>Tip: Disable auto-filled forms for sensitive data.</em></p>
<h3 id="heading-secure-http-requests">Secure HTTP requests</h3>
<p>When making HTTP requests, ensure they are secure by using HTTPS. HTTPS uses TLS to encrypt HTTP traffic, improving safety and security.</p>
<p>So, why is using HTTPS so important? First of all, using HTTPS is more secure for both the user and the web server, as the encryption goes both ways: from the server to the end user and vice versa. This way, none of the information transmitted during the connection is in a plain text, preventing attacks such as man-in-the-middle. Secondly, an SSL certificate authenticates the website, meaning that a trustworthy third party verifies that the web server is who it is claimed to be, protecting the user against threats like website proofing.</p>
<p>These days, using HTTPS is a must in order to gain the trust of potential customers for your website, ensuring basic security through an encrypted connection. It is important to mention that any website without a valid SSL certificate is automatically flagged as “unsecure“.</p>
<h3 id="heading-penetration-testing">Penetration Testing</h3>
<p>Web applications are critical systems as they are directly exposed to the outside world. Given this criticality, you should be worried about how secure your network is. The only way to truly know is by putting it to the test.</p>
<p>The practice of penetration testing proves to be a valuable asset in detecting vulnerabilities before they can be exploited by malicious actors. By thoroughly evaluating the security measures in place, potential weaknesses can be identified and addressed, reducing the risk of successful cyber attacks. The proactive approach to security reinforces the importance of maintaining a comprehensive and robust security strategy.</p>
<p>During a vulnerability assessment, some crucial types of attacks are being tested for:</p>
<ul>
<li><p>Injection attacks</p>
</li>
<li><p>Broken access control</p>
</li>
<li><p>Improper error handling</p>
</li>
<li><p>Broken authentication</p>
</li>
<li><p>XSS attacks</p>
</li>
</ul>
<p>Sometimes, the people who create your applications may make mistakes. To ensure that, your team’s work is error-free, you can ask an external partner to conduct a penetration test. This test helps to identify and fix any weak spots that could be exploited by hackers. In applications that must comply with PCI DSS or HIPAA regulations, penetration testing is mandatory. It’s considered one of the most effective ways to protect your network from hacking attempts.</p>
<h3 id="heading-implementing-a-web-application-firewall-waf">Implementing a Web Application Firewall (WAF)</h3>
<p>A Web Application Firewall (WAF) is a security device that monitors and filters HTTP traffic to and from a web application. It can be used to protect against various types of attacks, including SQL injection, cross-site scripting (XSS), and cross-site request forgery (CSRF).</p>
<p>You can set up a WAF in front of your React application to protect it from attacks. The WAF will inspect all incoming requests and block any that are deemed malicious. It can also be configured to block requests that contain a specific pattern or match a set of rules.</p>
<p>For example, you can configure the WAF to block requests containing SQL injections or XSS attacks. You can also configure it to block requests containing CSRF tokens stolen from other websites.</p>
<p>A WAF can be implemented in three ways:</p>
<ul>
<li><p><strong>As a hardware appliance</strong> - This is the most expensive option but provides the best performance and security</p>
</li>
<li><p><strong>As a software application</strong> - This is a cheaper option, but it requires more maintenance and configuration</p>
</li>
<li><p><strong>As a cloud service</strong> - This is the cheapest option, but it provides the least amount of control over the WAF.</p>
</li>
</ul>
<h3 id="heading-using-linter-plugins-and-code-analysis-tools">Using Linter plugins and code analysis tools</h3>
<p>Linters are tools that analyze your source code to flag programming errors, bugs, stylistic errors, and suspicious constructs. They can be used to improve the quality of your code and reduce the number of bugs in your application.</p>
<p>There are many linters available for React applications, including <strong>ESLint</strong> and <strong>JSLint</strong>. These tools can be used to enforce coding standards and detect common mistakes in your code. For example, they can be configured to flag unused variables, missing semicolons, and other common errors.</p>
<p>You can also use code analysis tools like <strong>SonarQube</strong> to analyze your code and identify potential security vulnerabilities. These tools can be used to detect security vulnerabilities.</p>
<h3 id="heading-applying-the-principle-of-least-privilege-polp">Applying the Principle of Least Privilege (PoLP)</h3>
<p>The Principle of Least Privilege (PoLP) states that every user should be given the minimum amount of privileges necessary to perform their job. This helps prevent unauthorized access to sensitive information and resources.</p>
<p>This means that you should only give users access to the resources they need to perform their job. For example, if a user only need to view a particular pages, they should not be allowed to edit it.</p>
<p>In a Reactjs application, you can implement the PoLP by using role-based access control (RBAC). This allows you to define roles for different types of users and assign permissions to those roles. For example, you can define an “admin“ role and assign it permission to edit pages.</p>
<h3 id="heading-http-security-headers-and-how-to-set-them-in-nextjs">HTTP Security Headers and How to Set Them in Next.js</h3>
<p>Security Headers are a type of HTTP header that helps us describe our site so we can help protect it against various potential attacks.</p>
<p><strong>What is a Security Header</strong></p>
<p>An HTTP (HyperText Transfer Protocol) header is simply something that we use to pass some extra information with HTTP requests and responses. Think of them as notes that give more context to the main document. Each header is simply a key-value pair separated by a colon.</p>
<p>When you visit a website, the server receives a request from the browser. This is a request for more information about the site you are visiting, which is exchanged from the HTTP request headers. The server then responds, and the response will include HTTP response headers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743502274118/5467947e-6f40-42bb-8dfd-5780624c5a85.png" alt class="image--center mx-auto" /></p>
<p>An example of the HTTP Header is the “Authorization“ header. It simply authenticates the user agent (software that acts on behalf of a user) with a server.</p>
<p><code>Authorization: Bearer &lt;Some token&gt;</code></p>
<p>So what is an HTTP security header?</p>
<p>We use security headers to help describe our sites, specifically to protect against various potential attacks. When a user navigates to the site, the server will respond with response headers that provide the browser with information on how to handle things.</p>
<p>By adding security headers to the response of our pages, we can minimize the possibility of the following attacks happening in our application.</p>
<ul>
<li><p>Cross-Site Scripting (XXS)</p>
</li>
<li><p>Clickjacking</p>
</li>
<li><p>Code injection</p>
</li>
</ul>
<p><strong>Examples of Security Headers</strong></p>
<p>Let’s take a look at some of the important security headers that you may want to implement:</p>
<p>If you are already familiar with security headers, skip ahead and set them up in Next.js here - <a target="_blank" href="https://blog.kieranroberts.dev/http-security-headers-and-how-to-set-them-in-nextjs#adding-security-headers-to-a-nextjs-app">Adding security headers to a Next.js app</a>.</p>
<ol>
<li><strong>Content Security Policy</strong></li>
</ol>
<p>The content security policy header allows you to set a policy for which domains are executable scripts. It’s like setting a policy for children in a video streaming service. You can specify what they can and cannot watch and it’s the same idea here.</p>
<p>Sometimes, your site will need to execute scripts that come from origins other than your own application. With this header, we can fine-tune exactly which domains should be considered safe or ‘whitelisted‘ and which should not.</p>
<p>We can also control the kind of resources we load into the site in more detail. For example, we could restrict loading scripts to our own domain but allow fonts or images to be loaded from a specific outside source.</p>
<p>Let’s take a look at a few examples:</p>
<p>To allow content from any domain as if the policy was not set</p>
<p><code>Content-Security-Policy: default-src *</code></p>
<p>Or set the own origin as the only trusted domain.</p>
<p><code>Content-Security-Policy: default-src 'self'</code></p>
<p>You can also specify any domain other than your own trusted domain.</p>
<p><code>Content-Security-Policy: default-src 'https://someotherdomain.com'</code></p>
<p>We can fine-tune our content security policy to set separate policies for resources like images, fonts, styles, media, scripts, and more like this</p>
<p><code>Content-Security-Policy: default-src 'self'; font-src 'self' 'https://fonts.googleapis.com'; image-src *.somewhere.com; script-src 'self'</code></p>
<p>In the above policy, we set the following:</p>
<ul>
<li><p>We set the default source for the content as our site’s origin, so this will be used for all resources unless otherwise specified.</p>
</li>
<li><p>We allow fonts to be loaded from our own site or from Google fonts</p>
</li>
<li><p>Images can be trusted from anywhere that ends in <code>.somewhere.com</code></p>
</li>
<li><p>Scripts are only trusted from our own site</p>
</li>
</ul>
<ol start="2">
<li><strong>Permissions Policy (Previously ‘Feature Policy‘)</strong></li>
</ol>
<p>The recently renamed Permissions Policy Security header allows you to control which browser APIs are allowed to be used within your site document or any frames located in the document.</p>
<p>Things like geolocation, camera, microphone, and many more can all be disabled if you know your site does not require them, which can reduce the possibility of attacks coming through these avenues.</p>
<p><code>Permissions-Policy: camera=(); battery=(self); geolocation=(); microphone=('https://somewhere.com')</code></p>
<p>In the above example, we set the policies of several browser features:</p>
<ul>
<li><p>The camera is empty, which means we deny the use of video input devices.</p>
</li>
<li><p>Battery Status API is allowed within your own domain</p>
</li>
<li><p>Geolocation is empty, which means we deny its use</p>
</li>
<li><p>Audio input devices are allowed for the origin stated</p>
</li>
</ul>
<ol start="3">
<li><strong>X-Frame-Options</strong></li>
</ol>
<p>The X-Frame-Options header controls whether or not your site can be loaded within a frame. Allowing this can be dangerous because you leave yourself open to clickjacking attacks.</p>
<p>Clickjacking is an attack that involves tricking the user into clicking something that they believe to be something else. Attackers may disguise elements, and the user is unable to see what they are actually clicking on.</p>
<p>We can help protect ourselves against this attack by preventing our site from being loaded within a frame.</p>
<p>There are two options for this header:</p>
<p><code>X-Frame-Options: deny</code></p>
<p>This recommended option is to deny your site being loaded in frames, which is shown above using the ‘deny‘ option:</p>
<p><code>X-Frame-Options: SAMEORIGIN</code></p>
<p>The “SAMEORIGIN“ option allows the site to be loaded within a frame while serving the site is the same as the one in the frame.</p>
<ol start="4">
<li><strong>X-Content-Type-Options</strong></li>
</ol>
<p>The X-Content-Type-Options header ensures that the MIME (Multipurpose Internet Mail Extensions) types specified in Content-Type are adhered to, and we avoid what is known as ‘MIME type sniffing‘. Browsers might try and determine the MINE type based on the response content instead of what is specified in the Content-Type header.</p>
<p>It only has one option, and it prevents the browser from trying to change the Content-Type away from what was declared.</p>
<p><code>X-Content-Type-Options: nosniff</code></p>
<ol start="5">
<li><strong>Referrer policy</strong></li>
</ol>
<p>With this header, we can control what information is sent when a user navigates from one origin to another. Consider a user that clicks a link on what we will call the original site. This link takes a user to a different domain. When this happens, some information is sent to the new domain. Information about where the user came from.</p>
<p>There are several different options we can set with this header.</p>
<p><code>Referrer-Policy: origin-when-cross-origin</code></p>
<p>The ‘origin-when-cross-origin‘ options send the path, origin, and query string with the same-origin request from equal protocol levels. An example of an equal protocol level would be from HTTPS to HTTPS:</p>
<p>If the request is cross-origin, only the origin is sent.</p>
<p><code>Referrer-Policy: strict-origin-when-cross-origin</code></p>
<p>The 'strict-origin-when-cross-origin' option is similar to the previous option. The path, origin, and query string are included with same-origin requests regardless of protocol level.</p>
<p>When making cross-origin requests, only the origin is sent as long as the protocol level is the same and omits the header otherwise.</p>
<p><code>Referrer-Policy: strict-origin</code></p>
<p>With 'strict-origin', only the origin is sent when the protocol level is equal and otherwise omits the header.</p>
<p><code>Referrer-Policy: no-referrer</code></p>
<p>The 'no-referrer' setting will omit the referrer header.</p>
<p>There are further options that you can check out <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy"><strong>here</strong></a></p>
<ol start="6">
<li><strong>Strict Transport Security</strong></li>
</ol>
<p>With the Strict Transport Security header, you can specify that your site should only be accessed using the HTTPS Protocol. Here, we can specify the time in seconds that the browser will remember this protocol.</p>
<p><code>Strict-Transport-Security: max-age=31536000;</code></p>
<p>You can also extend the instruction to all subdomains with all optional settings:</p>
<p><code>Strict-Transport-Security: max-age=31536000; includeSubDomains</code></p>
<p>You may think that setting up a redirect from ‘http://' to 'https://' is enough, but attackers could still seize sensitive information. Setting up a Strict Transport Security setting will make this attack far more difficult.</p>
<p><strong>Adding Security Headers to a Next.js App</strong></p>
<p>Now that we've had a look at some security headers, let's quickly implement them in a Next.js app. Also, feel free to explore some of the other security headers available.</p>
<p>In Next.js, we can set security headers from a <code>next.config.js</code> file located at the root of your project.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// next.config.js</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  <span class="hljs-keyword">async</span> headers() {
    <span class="hljs-keyword">return</span> [

    ]
  },
};
</code></pre>
<p>We return an array of headers that we specify inside JavaScript objects. You can choose to apply headers that will be sent with every route request or on a route-by-route basis. Let's set some of the headers that we previously explored.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// next.config.js</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  <span class="hljs-keyword">async</span> headers() {
    <span class="hljs-keyword">return</span> [
        {
          source: <span class="hljs-string">'/(.*)'</span>,
          headers: [
            {
              key: <span class="hljs-string">'Content-Security-Policy'</span>,
              value:
                <span class="hljs-string">"default-src 'self'; font-src 'self' 'https://fonts.googleapis.com'; img-src 'self' *.somewhere.com; script-src 'self'"</span>,
            },
            {
              key: <span class="hljs-string">'X-Frame-Options'</span>,
              value: <span class="hljs-string">'DENY'</span>,
            },
            {
              key: <span class="hljs-string">'X-Content-Type-Options'</span>,
              value: <span class="hljs-string">'nosniff'</span>,
            },
            {
              key: <span class="hljs-string">'Referrer-Policy'</span>,
              value: <span class="hljs-string">'origin-when-cross-origin'</span>,
            },
            {
              key: <span class="hljs-string">'Permissions-Policy'</span>,
              value: <span class="hljs-string">"camera=(); battery=(self); geolocation=(); microphone=('https://somewhere.com')"</span>,
            },
          ],
        },
      ];
  },
};
</code></pre>
<p>In the above example, we set our security headers for all routes in our site indicated by the source <code>/(.*)</code>. You could also set security headers on a page-by-page basis like this 👇</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// next.config.js</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  <span class="hljs-keyword">async</span> headers() {
    <span class="hljs-keyword">return</span> [
        {
          source: <span class="hljs-string">'/profile'</span>,
          headers: [
            {
              key: <span class="hljs-string">'Content-Security-Policy'</span>,
              value:
                <span class="hljs-string">"default-src 'self'; font-src 'self' 'https://fonts.googleapis.com'; img-src 'self' *.somewhere.com; script-src 'self'"</span>,
            }
          ]
        },
       {
          source: <span class="hljs-string">'/blog'</span>,
          headers: [
            {
              key: <span class="hljs-string">'Content-Security-Policy'</span>,
              value:
                <span class="hljs-string">"default-src 'self'"</span>,
            }
          ]
        },
      ];
  },
};
</code></pre>
<p>Now, spin up a development server in your Next.js application and navigate to the route after setting your security headers. You should be able to see the headers you set in the network tab of the developer console.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743587312710/a3aa1e19-1cbc-4c25-b631-d4bec73ad759.png" alt class="image--center mx-auto" /></p>
<p>Congratulations, your site is more secure than it was before. Customize the security header to suit your application, as each site has its own specific requirements.</p>
<h3 id="heading-best-practices-for-storing-access-tokens-in-the-browser">Best Practices for Storing Access Tokens in the Browser</h3>
<p>Browsers offer various solutions to persist data. When storing tokens, you should weigh the choice of storage against the security risks.</p>
<p>Web applications are not static sites but a careful composition of static and dynamic content. More often than not, the application logic runs in the browser. Instead of fetching all content from the server, the application runs Javascript under the browser that fetches data from the backend API and updates the web application presentation accordingly.</p>
<p>To protect access to data, organizations should employ OAuth 2.0 With OAuth 2.0, a Javascript application needs to add an access token to every request to the API. For usability reasons, Javascript applications don’t usually request the access token on demand but store it. The question is, how do you obtain such an access token within Javascript? And when you get one, where should the application store the token so that it can add it to the request when needed?</p>
<p>This section discusses different storage solutions available in <a target="_blank" href="https://thenewstack.io/what-does-it-mean-for-web-browsers-to-have-a-baseline/">browsers</a> and highlights the security risks associated with each option. After reviewing the threat, it describes a solution in the form of a pattern that provides the best browser security options for <a target="_blank" href="https://thenewstack.io/beyond-browsers-the-longterm-future-of-javascript-standards/">Javascript applications</a> that must integrate with <a target="_blank" href="https://thenewstack.io/5-steps-to-modernize-large-websites-using-oauth/">OAuth-protected APIs</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743853170691/d5169159-590f-4e9a-98b2-402d8e977077.jpeg" alt class="image--center mx-auto" /></p>
<p>For more details, check out <a target="_blank" href="https://thenewstack.io/best-practices-for-storing-access-tokens-in-the-browser/?ref=dailydev">this useful article</a>.</p>
<h2 id="heading-references">References</h2>
<p><a target="_blank" href="https://www.freecodecamp.org/news/how-attackers-steal-data-from-websites-and-how-to-stop-them/?ref=dailydev">https://www.freecodecamp.org/news/how-attackers-steal-data-from-websites-and-how-to-stop-them/?ref=dailydev</a></p>
<p><a target="_blank" href="https://otherurl.com/js/*">https</a><a target="_blank" href="https://blog.bitsrc.io/frontend-application-security-tips-practices-f9be12169e66">://blog.bitsrc.io/frontend-application-security-tips-practices-f9be12169e66</a></p>
<p><a target="_blank" href="https://blog.bitsrc.io/top-7-frontend-security-attacks-2e2b56dc2bcc">https://blog.bitsrc.io/top-7-frontend-security-attacks-2e2b56dc2bcc</a></p>
<p><a target="_blank" href="https://griddynamics.medium.com/front-end-security-best-practices-8c47d23caf62">https://griddynamics.medium.com/front-end-security-best-practices-8c47d23caf62</a></p>
<p><a target="_blank" href="https://dev.to/akshay_varma/mitigating-xss-risks-best-practices-for-web-applications-2e04?context=digest">https://dev.to/akshay_varma/mitigating-xss-risks-best-practices-for-web-applications-2e04?context=digest</a></p>
<p><a target="_blank" href="https://medium.com/@eddyos05/security-practices-that-frontend-developers-should-know-6bcc2b8ebbbd">https://medium.com/@eddyos05/security-practices-that-frontend-developers-should-know-6bcc2b8ebbbd</a></p>
<p><a target="_blank" href="https://dev.to/rigalpatel001/preventing-clickjacking-attacks-in-javascript-39pj?context=digest">https://dev.to/rigalpatel001/preventing-clickjacking-attacks-in-javascript-39pj?context=digest</a></p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/types-of-cyber-attacks-to-know/">https://www.freecodecamp.org/news/types-of-cyber-attacks-to-know/</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/cors-finally-explained-simply-ae42b52a70a3">https://levelup.gitconnected.com/cors-finally-explained-simply-ae42b52a70a3</a></p>
<p><a target="_blank" href="https://blog.bitsrc.io/enhance-javascript-security-with-content-security-policies-5847e5def227">https://blog.bitsrc.io/enhance-javascript-security-with-content-security-policies-5847e5def227</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/frontend-app-security-439797f57892">https://medium.com/better-programming/frontend-app-security-439797f57892</a></p>
<p><a target="_blank" href="https://blog.kieranroberts.dev/http-security-headers-and-how-to-set-them-in-nextjs">https://blog.kieranroberts.dev/http-security-headers-and-how-to-set-them-in-nextjs</a></p>
<p><a target="_blank" href="https://www.turing.com/kb/reactjs-security-best-practices?ref=dailydev#using-https">https://www.turing.com/kb/reactjs-security-best-practices?ref=dailydev#using-https</a></p>
]]></content:encoded></item><item><title><![CDATA[SEO Handbook]]></title><description><![CDATA[SEO (Search Engine Optimization) is essential for your online marketing strategy. It’s the process of optimizing your site and content to help you get as much traffic as you can from search engines.
Reaching top positions in the Search Engine Results...]]></description><link>https://blog.tuanhadev.tech/seo-handbook</link><guid isPermaLink="true">https://blog.tuanhadev.tech/seo-handbook</guid><category><![CDATA[SEO]]></category><category><![CDATA[Accessibility]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Sat, 22 Mar 2025 12:15:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/yIRdUr6hIvQ/upload/c19ce089924d702b7be0bd6c67042bcf.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>SEO (Search Engine Optimization) is essential for your online marketing strategy. It’s the process of optimizing your site and content to help you get as much traffic as you can from search engines.</p>
<p>Reaching top positions in the Search Engine Results Pages (SERPs) with your website is one of the fastest ways to drive traffic to your site and boost conversions.</p>
<h1 id="heading-seo-fundamentals">SEO Fundamentals</h1>
<p>Amidst the economic devastation of COVID-19, online businesses have become more dependent on SEO than ever. Times like these illustrate the power and importance of Search Engine Optimization (SEO).</p>
<h2 id="heading-what-is-seo">What is SEO?</h2>
<p>SEO is the practice of increasing the quantity and quality of traffic to a web page through organic search engine results. Organic search results are derived from an internal algorithm of the search engine and are not a result of paid advertising. Below is a list of related terminology:</p>
<ul>
<li><p><strong>SERP</strong>, or Search Engine Results Page, is simply the results page that drives clicks. These pages include a combination of paid search results and organic results.</p>
</li>
<li><p><strong>SEM</strong>, or Search Engine Marketing, is the practice of marketing a business using the paid advertisements that appear on SERPs.</p>
</li>
<li><p><strong>PPC</strong> stands for pay-per-click, an internet marketing model in which advertisers pay a fee each time their ads are clicked.</p>
</li>
</ul>
<p>Learning SEO basics and more advanced topics can be a bewildering process. In this post, we will examine simple steps to help create SEO-friendly web pages and tools for maintaining them.</p>
<h2 id="heading-web-accessibility-and-performance">Web Accessibility and Performance</h2>
<p>Search Engines will surely continue to raise the bar for acceptable web standards. <a target="_blank" href="https://webmasters.googleblog.com/2018/03/rolling-out-mobile-first-indexing.html">In 2018, Google announced the beginning of its migration to mobile-first indexing</a> and expanded by announcing <a target="_blank" href="https://webmasters.googleblog.com/2020/03/announcing-mobile-first-indexing-for.html">mobile-first indexing for the whole web in 2020</a>. Web page performance and accessibility encompass user-centric metrics that can ultimately impact SEO.</p>
<p>Web performance captures the user journey, making various moments of the user experience. Below are important performance metrics:</p>
<ul>
<li><p><a target="_blank" href="https://web.dev/fcp/">First Contentful Paint (FCP)</a> measures the time from when the page starts loading to when any part of its content is rendered on the screen.</p>
</li>
<li><p><a target="_blank" href="https://web.dev/lcp/">Largest Contentful Paint (LCP)</a> measures the time from the page's start loading to the time the largest text block or image element is rendered on the screen.</p>
</li>
<li><p><a target="_blank" href="https://web.dev/fid/">First-input Delay (FID)</a> measures the time between when a user first interacts with your site (e.g., when they click on a link, tab a button, or use a custom, Javascript-powered control) and when the browser is actually able to respond to that interaction.</p>
</li>
<li><p><a target="_blank" href="https://web.dev/tti/">Time To Interactive (TTI)</a> measures the time from when the page starts loading to when it’s visually rendered, its initial scripts (if any) have loaded, and it can reliably respond to user input quickly.</p>
</li>
<li><p><a target="_blank" href="https://web.dev/tbt/">Total Blocking Time (TBT)</a>: measures the total amount of time between FCP and TTI when the main thread was blocked for long enough to prevent input responsiveness.</p>
</li>
<li><p><a target="_blank" href="https://web.dev/cls/">Cumulative Layout Shift (CLS)</a>: measures the cumulative score of all unexpected layout shifts that occur between when the page starts loading and when its <a target="_blank" href="https://developers.google.com/web/updates/2018/07/page-lifecycle-api">lifecycle state</a> changes to hidden.</p>
</li>
</ul>
<p>Web accessibility is another important concept to keep in mind when building a search engine optimized website. Not only are there a variety of humans reading our websites, but also a variety of machines like screen-readers doing the same.</p>
<p>Improving accessibility makes your website more useable to everyone ~ Addy Osami | <a target="_blank" href="https://web.dev/a11y-tips-for-web-dev/">Accessibility Tips for Web Developers</a>.</p>
<h2 id="heading-seo-tools">SEO Tools</h2>
<p>In this post, we have taken a look at ways to improve SEO, but how do we maintain these standards over time? Many tools can help us analyze and monitor SEO.</p>
<p><a target="_blank" href="https://www.foo.software/lighthouse">Foo’s Automated Lighthouse Check</a> monitors the quality of web pages with Lighthouse. It provides detailed SEO, performance, and accessibility reporting. Free and premium plans are available.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741514286819/95452430-db56-46a0-a459-78babf89399c.png" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://search.google.com/search-console/about">Google Search Console</a> is a must-have for any website owner who cares about SEO. It provides insight into which search terms are receiving organic traffic and a granular level of analysis. You can filter by location, device, and more.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741514534049/6c01ee40-87ec-4fbb-9cc8-a715ddb47017.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-benefits-of-seo-in-web-development">Benefits of SEO in Web Development</h2>
<p>Every business owner wants to grow his or her brand. Search Engine Optimization (SEO) greatly benefits organizations that provide value and boost visibility to the target audience. The following are some of the benefits of integrating SEO into website development.</p>
<ol>
<li><p>SEO boosts high-quality traffic and organic discovery. Organic visibility leads to increased traffic, which is a monumental SEO benefit. Search engine optimization is customer-centric and hyper-targeted. An effective SEO strategy helps deliver web pages to the relevant people through pertinent search queries. Since users are already looking for what a site has to offer, organic visibility propels high-quality traffic without trying to persuade ot entice the visitor.</p>
</li>
<li><p>SEO Boosts Credibility Ranking on Google’s first page showcases credibility to prospective customers. Google ranks websites based on on-page and off-page signals, such as site speed, content, and mobile usability. Although most customers probably don’t consider these signals, users expect Google to deliver valuable and relevant content first. Trust and credibility are developed on search engine authority and a high-quality service or product that builds credibility among web visitors or users.</p>
</li>
<li><p>SEO provides an Impressive ROI ROI, or Return on Investment, which is vital when evaluating digital marketing channels. Although search engine optimization could take some time to get results, a high-quality strategy will ultimately deliver an impressive return on investment. Search engine leads offer a 14.6 percent close rate, almost 12 percent greater than traditional marketing. Nevertheless, there would be no leads if a website ranks at the bottom of pages 2, 3, 4, or not at all. Visibility in search engines correlates directly to improved web traffic and more revenue, making ROI one of the most significant benefits of SEO for organizations.</p>
</li>
<li><p>SEO Targets the Marketing Funnel Driven by SEO, content marketing includes different types of targeting at each marketing funnel step. Although top or middle-of-the-funnel blog posts will not initially convert, this builds brand awareness and loyalty. These traits will lead to conversion.</p>
</li>
</ol>
<h2 id="heading-seo-techniques">SEO Techniques</h2>
<p>The website optimization process meets the Google algorithm requirements in a way that equals building a website that corresponds to the user’s requirements. Users appreciate the fast-loading website that is error-free and can be browsed seamlessly on mobiles. That said, let’s explore the fundamentals that every web developer should know.</p>
<h3 id="heading-website-loading-time">Website Loading Time</h3>
<p>Website speed and loading time are the most important after ensuring your website can be indexed. The <a target="_blank" href="https://pagespeed.web.dev/">page speed test of a website</a> with a good search result is vital; thus, it’s an essential factor to consider when it comes to website design. <a target="_blank" href="https://www.semrush.com/blog/page-speed/">According to Semrush</a>, a slow page response increases <a target="_blank" href="https://blog.openreplay.com/how-to-reduce-your-websites-bounce-rate/">the website bounce rate</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741598680424/b211ca23-d0a2-42c0-bfb0-180d78c19f9e.png" alt class="image--center mx-auto" /></p>
<p>Unsurprisingly, these users will skip over the website if it takes a second longer to load. Furthermore, a slow-loading website could also affect its search engine ranking. It would be challenging for an SEO expert to boost its rank with SEO content. Therefore, it’s highly recommended that developers integrate SEO into the development process, work closely with SEO experts, or learn core web vitals SEO principles in <a target="_blank" href="https://blog.openreplay.com/key-metrics-at-google-search-console/">Google search console metrics</a> about Website speed and performance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741599141266/ea3d0564-210d-4870-aa02-6c54cca2a4b6.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-redirects">Redirects</h3>
<p>The digital landscape will continue to evolve. Furthermore, everyone is recreating and improving their own sites and domains with advanced features. Another important factor in SEO for web development is Redirects. Redirects smoothly lead users to the correct page during site migration and launch. For web developers, using 301 and 302 redirect codes is paramount. Don’t just rely on the code to be rendered. Rather, use tools to test the redirect codes, no matter how many pages are being redirected to the same destination. Redirects send users from URL to URL. The first URL is where users click, type, or make a request. The second URL is the new destination.</p>
<p>When to use 301 Redirects.</p>
<ul>
<li><p>If you are changing the page URL</p>
</li>
<li><p>Domain Migration from page to page</p>
</li>
<li><p>If you want to pass the page authority to the new page.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741599689290/cc3bca76-48e3-4d21-8eef-45f3111d2112.png" alt class="image--center mx-auto" /></p>
<p>When to use 302 Redirects</p>
<ul>
<li><p>If you are making any changes to the current page.</p>
</li>
<li><p>If you don’t want to pass the page authority.</p>
</li>
<li><p>At some point in the future, the old page will be back.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741599929039/b8cab843-bc4d-4130-8878-3308e03cb8cd.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-sitemaps">Sitemaps</h3>
<p>When it comes to search engine optimization, better crawlability plays an important role. When a search engine attempts to index a website, it should be able to crawl the whole website. <a target="_blank" href="https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview">Sitemaps are valuable</a> if there are issues indexing the website. Adding a sitemap ensures that the website is properly indexed. Moreover, ensure that all pages listed in the XML sitemap do not have wasteful redirects, are error-free, and have clean code. From creating content to design to CEO, the sitemap is invaluable. You will constantly refer to it in the stages of development to stay on track. Sitemaps tell Google which files and pages you think are important and provide valuable information regarding these files. Here’s a simple example of the XML sitemap.</p>
<pre><code class="lang-typescript">&lt;?xml version=<span class="hljs-string">"1.0"</span> encoding=<span class="hljs-string">"UTF-8"</span>?&gt;
&lt;urlset xmlns=<span class="hljs-string">"http://www.sitemaps.org/schemas/sitemap/0.9"</span>&gt;
&lt;url&gt;
&lt;loc&gt;https:<span class="hljs-comment">//www.example.com/foo.html&lt;/loc&gt;</span>
&lt;lastmod&gt;<span class="hljs-number">2022</span><span class="hljs-number">-06</span><span class="hljs-number">-04</span>&lt;/lastmod&gt;
&lt;/url&gt;
&lt;/urlset&gt;
</code></pre>
<h3 id="heading-robotstxt">Robots.txt</h3>
<p>A robots.txt file is a simple text file on a website that tells search engines which pages they can and cannot visit.</p>
<pre><code class="lang-xml">Sitemap: https://acidop.codes/sitemap.xml
User-agent: *
Allow: /
Disallow: /admin
</code></pre>
<p>In the above example, we submit our sitemap and also clearly state that we do not want to index our admin directory.</p>
<h3 id="heading-mobile-responsiveness">Mobile Responsiveness</h3>
<p>Without a doubt, a website that is <a target="_blank" href="https://developers.google.com/search/blog/2016/03/continuing-to-make-web-more-mobile">mobile-responsive</a> provides a better user experience. Furthermore, a responsive design helps them navigate the website easily without zooming in or zooming out of the content. Smartphones are getting smarter, and search engines keep setting higher bars for mobile SEO factors. A mobile-friendly website will always rank better than a desktop-supported website. Thus, web developers must ensure that the website is compatible with a wide array of devices for good search engine optimization. Furthermore, Google uses <a target="_blank" href="https://developers.google.com/search/blog/2020/03/announcing-mobile-first-indexing-for">mobile-first indexing</a>, meaning that the mobile version of the website gets crawled first.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741605812840/3e7eca89-c3aa-4b5a-a8be-fbfc4ac44cef.png" alt class="image--center mx-auto" /></p>
<p>In the above image, you can see that in the Google Search Console, the primary crawler is a smartphone. Simply put, a mobile-responsive design is when a site is responsive, as the content and/or layout responds to the screen size on which it is displayed. Moreover, a responsive website adapts itself to the advice used to see it. Use Google’s <a target="_blank" href="https://search.google.com/test/mobile-friendly">mobile-friendly testing tool</a> to get your website report.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741606162041/b584b1c5-cc36-43eb-9b6e-ebc2edd83413.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-implement-structured-data">Implement Structured Data</h3>
<p>For most people involved in SEO, structured data could be knotty. This is where developers could truly shine. Developers already know how to format a page so all the parts will flow well and can be read by humans and search engines alike. When used well, <a target="_blank" href="https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data">structured data</a> lets Google know where and what’s on the web page. Furthermore, it could also inform Google precisely what questions you are answering. Structured data is a way for the business website to convey its content to search engines. It boosts visibility. Google uses structured data on web pages to generate snippets, which display special enhancements in SEO results. Regardless of whether they appear at the top or bottom on the search results page, rich snippets are way more visible and prominent than the standard results, and therefore, the click-through rates are much better. Take a look at an example of SERP with and without structured data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741607808293/43e7a38b-1262-4622-a5e9-e397eadc32fe.png" alt class="image--center mx-auto" /></p>
<p>In the above example, rating (Review, AgreegateRating) markup has been used.</p>
<p>Google, Bing, Yandex, and Yahoo! worked together to create <a target="_blank" href="https://schema.org/">Schema.org</a> so you could provide search engines the data they require to understand your content and deliver the most relevant results.</p>
<p>You can use any of the 3 methods <a target="_blank" href="https://developers.google.com/search/docs/appearance/structured-data/sd-policies#technical-guidelines">suggested by Google</a>:</p>
<ul>
<li><p><a target="_blank" href="https://json-ld.org/">Json-Id</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Microdata_\(HTML\)">Microdata</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/RDFa">RDFa</a></p>
</li>
</ul>
<p>JSON-LD is the format Google recommends and is also the easiest one to implement.</p>
<p>Take a look at an example of how review markup can be implemented.</p>
<pre><code class="lang-xml"><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>Legal Seafood<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"application/ld+json"</span>&gt;</span><span class="javascript">
  {
   <span class="hljs-string">"@context"</span>: <span class="hljs-string">"https://schema.org/"</span>,
   <span class="hljs-string">"@type"</span>: <span class="hljs-string">"Review"</span>,
   <span class="hljs-string">"itemReviewed"</span>: {
    <span class="hljs-string">"@type"</span>: <span class="hljs-string">"Restaurant"</span>,
    <span class="hljs-string">"image"</span>: <span class="hljs-string">"https://www.example.com/seafood-restaurant.jpg"</span>,
    <span class="hljs-string">"name"</span>: <span class="hljs-string">"Legal Seafood"</span>,
    <span class="hljs-string">"servesCuisine"</span>: <span class="hljs-string">"Seafood"</span>,
    <span class="hljs-string">"priceRange"</span>: <span class="hljs-string">"$$$"</span>,
    <span class="hljs-string">"telephone"</span>: <span class="hljs-string">"1234567"</span>,
    <span class="hljs-string">"address"</span> :{
     <span class="hljs-string">"@type"</span>: <span class="hljs-string">"PostalAddress"</span>,
     <span class="hljs-string">"streetAddress"</span>: <span class="hljs-string">"123 William St"</span>,
     <span class="hljs-string">"addressLocality"</span>: <span class="hljs-string">"New York"</span>,
     <span class="hljs-string">"addressRegion"</span>: <span class="hljs-string">"NY"</span>,
     <span class="hljs-string">"postalCode"</span>: <span class="hljs-string">"10038"</span>,
     <span class="hljs-string">"addressCountry"</span>: <span class="hljs-string">"US"</span>
    }
   },
   <span class="hljs-string">"reviewRating"</span>: {
    <span class="hljs-string">"@type"</span>: <span class="hljs-string">"Rating"</span>,
    <span class="hljs-string">"ratingValue"</span>: <span class="hljs-string">"4"</span>
   },
   <span class="hljs-string">"name"</span>: <span class="hljs-string">"A good seafood place."</span>,
   <span class="hljs-string">"author"</span>: {
    <span class="hljs-string">"@type"</span>: <span class="hljs-string">"Person"</span>,
    <span class="hljs-string">"name"</span>: <span class="hljs-string">"Bob Smith"</span>
   },
   <span class="hljs-string">"publisher"</span>: {
    <span class="hljs-string">"@type"</span>: <span class="hljs-string">"Organization"</span>,
    <span class="hljs-string">"name"</span>: <span class="hljs-string">"Washington Times"</span>
   }
  }
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</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>This JSON=LD script needs to be embedded in the HTML:</p>
<p>A special script tag: <code>&lt;script type="application/ld+json"&gt;</code> is used for this purpose. we can insert this into the head or the body of the HTML.</p>
<p>The same can be tested using the <a target="_blank" href="https://search.google.com/test/rich-results">Rich Results test</a> tool.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741608017773/fb0746a6-1259-4a24-aa05-e62722dab21e.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-user-friendly-urls">User-Friendly URLs</h3>
<p>Web developers should remember that URLs should be descriptive, concise, and easy to read to be effective. Both search engines and users like the quality of page addresses, which could easily be advantageous to your website. SEO guide for developers includes much information about bot-friendly writing URLs. You can, specifically, do the following:</p>
<ul>
<li><p>Use one domain and subdomain. A subdomain could generate mixed results; thus, using a single domain whenever possible is the best solution.</p>
</li>
<li><p>Make use of hyphens. Rather than spaces, bots refer hyphens to separate words in URLs.</p>
</li>
<li><p>Keywords. Add keywords to URLs where they naturally fit. Do not, however, use too much. Furthermore, refrain from making the URL too long so it won’t look spammy.</p>
</li>
<li><p>Get rid of unsafe characters. Some characters, such as carats, tildes, and spaces, could make bots stop in their tracks. Thus, it’s best to avoid them. Here are some user-friendly URL suggestions:</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741677710615/f3d13b7e-5c0f-4736-a938-91bfa5185ac5.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-website-security">Website Security</h3>
<p>To the search engines, website security is an absolute must. Regarding website development, web developers should make sure to <a target="_blank" href="https://developers.google.com/web/shows/cds/2013/got-ssl">have an SSL in place</a> and with no errors. Furthermore, it’s also necessary to have safeguards to ensure that the website doesn't have vulnerabilities.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741678376827/30ccccf0-d9f4-4052-a968-0ae2b6cd7603.png" alt class="image--center mx-auto" /></p>
<p>For every business these days, protecting a website against phishing, cyber-crimes, cyber-attacks, and malfunctions is paramount. Security testing is always needed to defend against data loss and theft caused by digital hackers. In the present scenario, cybersecurity has become a primary shield, and with technological advancement, you need to detect, monitor, upgrade, and patch continuously to avoid risks. From the beginning, website security features should be implemented to keep up with the new threats of continuous technological advancement. Furthermore, the security features should be monitored and maintained as well. Getting hacks hurts the user experience and could cause the site to slow down, lose traffic, lose sensitive client information, and crash. Google Search Console also gives us notifications related to security issues. Google Search Console with <a target="_blank" href="https://support.google.com/webmasters/answer/9044101?hl=en">website security issues</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741679401129/689217c4-c47e-4d46-9329-3f7193ecf180.png" alt class="image--center mx-auto" /></p>
<p>Google Search Console without website security issues.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741679473611/04baf607-fbde-4d6f-8d00-dd90d419867a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-title-tags-and-meta-descriptions">Title Tags and Meta Descriptions</h3>
<p>Here is how a title tag looks:</p>
<pre><code class="lang-xml"><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>AcidOP | Freelancing Developer<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>
</code></pre>
<p>Again, your goal is to tell a lot in a very short space. Technically, you don’t have a limit, but you should keep it to <a target="_blank" href="https://www.authorityhacker.com/seo-title-tags/">60 characters</a>.</p>
<p>The title should explain your niche or product related to your website and article.</p>
<p>Here’s how a description tag looks:</p>
<pre><code class="lang-xml"><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">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Excellent Developer from India."</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p>One of the most important elements in drawing visitors to a website is a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML#adding_an_author_and_description">meta description</a> tag:</p>
<p>The meta description should skillfully include the page’s target keywords to persuade readers to click through the page.</p>
<p>Search engines like Google frequently draw user attention by emphasizing terms from the query while displaying the description. It’s critical to match your description closely, but not excessively, to highly valuable search terms.</p>
<p>Below is a <code>title</code> and <code>description</code> tag in action:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741682187836/19c9b7c8-4b53-4dde-a3a4-5675fecd2397.jpeg" alt class="image--center mx-auto" /></p>
<p>Do not exceed <a target="_blank" href="https://yoast.com/meta-descriptions/#meta-description">155 characters</a> in descriptions, or Google will then truncate the text.</p>
<p><a target="_blank" href="https://www.w3schools.com/tags/tag_meta.asp">Here</a> is a list of other meta tags that you can use as well.</p>
<h3 id="heading-header-tags-h1-h2-h3-etc">Header Tags (H1, H2, H3, etc.)</h3>
<p><a target="_blank" href="https://www.w3schools.com/tags/tag_header.asp">Header tags</a> help your users navigate the page. The break up your content and break the page into dedicated sections.</p>
<p>Search engines rely on headers to better understand the sections of the page, which helps with SEO.</p>
<p>Instead of writing a very long article with a few paragraphs, divide it into multiple parts, each with its own heading, as I have done in this blog.</p>
<p>The main title of your document should be your <code>&lt;h1&gt;</code>. The <a target="_blank" href="https://backlinko.com/h1-tag">H1 Tag</a> represents the document’s overall topic and is displayed at the beginning as the large text.</p>
<p>Your main points should be wrapped in &lt;h2&gt;. <a target="_blank" href="https://www.techonthenet.com/html/elements/h2_tag.php">H2 tags</a> are second-level headings used to break up content and make it scanable and easy to read.</p>
<p>Subsequent heading tags lead all the way up to H6, which are not that important in the heading hierarchy.</p>
<ul>
<li><p>All the tags must be in the hierarchy, i.e., H1&gt;H2&gt;H3...H6.</p>
</li>
<li><p>There should only be 1 H1 tag in the entire document.</p>
</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>I built an Markdown editor using Next.js and TailwindCss 🔥<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>Objectives<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>1. Create the landing page<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>2. Add states to store data<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>3. Setup react-markdown and @tailwindcss/typography<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>4. Code Highlighting and Custom Components<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>Optional<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>5. Adding Rehype and Remark Plugins<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>6. Header with Markdown buttons<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
</code></pre>
<h3 id="heading-image-optimization-for-seo">Image Optimization for SEO</h3>
<p>According to Optinmonster, content that contains images <a target="_blank" href="https://optinmonster.com/blogging-statistics/">receives up to 94% more views</a>.</p>
<p>Visuals naturally captivate people, and nothing does it more effectively than a pleasing image.</p>
<p>This means that you must use visuals in your content to engage readers and increase your visibility.</p>
<p><strong>Using descriptive alt text</strong></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://acidop.codes/og.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"My website banner"</span> /&gt;</span>
</code></pre>
<p><a target="_blank" href="https://www.w3schools.com/TAGS/att_img_alt.asp">Alt Tags</a> (Technically, they are not tags; they are <a target="_blank" href="https://www.geeksforgeeks.org/tags-vs-elements-vs-attributes-in-html/">attributes</a>, but you don’t need to worry about that) are important for several key reasons.</p>
<ul>
<li><p><strong>Enhanced Accessibility</strong>: It assists visually impaired individuals in comprehending the image.</p>
</li>
<li><p><strong>SEO Boost</strong>: It offers search engines valuable details about the image, aiding in its visibility in search rankings.</p>
</li>
<li><p><strong>Improved User Experience</strong>: It conveys information about the image, even when it fails to load.</p>
</li>
</ul>
<p><strong>Choosing the right image formats:</strong></p>
<ul>
<li><p><a target="_blank" href="https://web.dev/learn/images/jpeg/">JPEGs</a> are good things like screenshots, blog post images, and content where <a target="_blank" href="https://acidop.codes/blogs/developer-seo-tips#6-site-speed">site speed</a> is essential.</p>
</li>
<li><p><a target="_blank" href="https://cloudinary.com/guides/image-formats/what-is-a-png-image-and-how-to-convert-it">PNG</a> is better for quality and resolution, but these files are typically larger, which can result in slower page load time.</p>
</li>
<li><p><a target="_blank" href="https://developers.google.com/speed/webp">WebP</a> offers superior compression capabilities compared to others, without comprising much on image quality. It enhances the load time of your web pages and minimizes bandwidth. It supports both the animated features of GIFs and the transparent backgrounds of PNGs.</p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/a-fresh-perspective-at-why-when-and-how-to-use-svg/">SVG</a> is best when it comes to icons and logos. They can be scaled to any size without losing resolution.</p>
</li>
</ul>
<p><strong>Implementing responsive images (srcset)</strong></p>
<p>Large graphics may slow down your website. We can speed up the process and <a target="_blank" href="https://html.com/attributes/img-srcset/">lower the file size,</a> but the visual quality remains the same on mobile devices as it does on desktop computers.</p>
<p><a target="_blank" href="https://html.com/attributes/img-srcset/">srcset</a> allows you to define a list of different image resources along with size information so the browser can pick the most appropriate image based on the actual device’s resolution.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
  <span class="hljs-attr">src</span>=<span class="hljs-string">"image.jpg"</span>
  <span class="hljs-attr">srcset</span>=<span class="hljs-string">"small.jpg 300w, medium.jpg 600w, large.jpg 900w"</span>
/&gt;</span>
</code></pre>
<h3 id="heading-canonical-tags-important">Canonical Tags (Important)</h3>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
    <span class="hljs-attr">rel</span>=<span class="hljs-string">"canonical"</span>
    <span class="hljs-attr">href</span>=<span class="hljs-string">"https://acidop.codes/blogs/developer-seo-tips"</span>
  /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p>In SEO, a <a target="_blank" href="https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls">canonical tag</a> is a link attribute that tells search engines which version of a web page is the original. This helps avoid confusion when multiple pages have similar or identical content.</p>
<p>Google is known to penalize sites with duplicate content.</p>
<p><a target="_blank" href="https://acidop.xn--codeshttps-yk10d://acidop.codes?utm_content=buffer">https://acidop.codes,</a></p>
<p><a target="_blank" href="https://acidop.xn--codeshttps-yk10d://acidop.codes?utm_content=buffer">https://acidop.codes?utm_content=buffer</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741867111787/8dcfb7cc-3b37-483a-a0b6-2a13016f4323.jpeg" alt class="image--center mx-auto" /></p>
<p>Even with UTM parameters, both point to the same page, right?</p>
<p>However, Google would consider both URLs to be different pages.</p>
<p>Having a propel canonical tag would help Google understand both are the same</p>
<p>For example, I write blogs on 2 sites: <a target="_blank" href="https://dev.to/acidop">Dev.to</a> (which supports canonical URLs) and my website. My primary source is my website obviously.</p>
<p>First, I post my blog on my website. Then I post the same blog on <a target="_blank" href="https://dev.to/acidop">dev.to</a> with a canonical URL pointing to my own website.</p>
<p>This way, I managed to get a bigger audience while also preventing Google from penalizing me.</p>
<h3 id="heading-regular-seo-audits-and-monitoring">Regular SEO Audits and Monitoring</h3>
<p>An SEO audit determines how optimized your website is for search engines. It identifies problems that could be harming the website’s rankings and offers ways to fix them.</p>
<p>Free tools for SEO audits:</p>
<ol>
<li><p><a target="_blank" href="https://aioseo.com/seo-analyzer/">Aioseo (<em>Best</em></a>)</p>
</li>
<li><p><a target="_blank" href="http://seoptimer.com">seoptimer.com</a></p>
</li>
<li><p><a target="_blank" href="https://seomator.com/free-tools">Seomat</a><a target="_blank" href="https://aioseo.com/seo-analyzer/">or</a></p>
</li>
<li><p><a target="_blank" href="https://www.seoptimer.com/">Seobi</a><a target="_blank" href="https://seomator.com/free-tools">l</a><a target="_blank" href="https://aioseo.com/seo-analyzer/">ity</a></p>
</li>
<li><p><a target="_blank" href="https://ahrefs.com/seo-audit-tool">S</a><a target="_blank" href="https://www.seoptimer.com/">emrus</a><a target="_blank" href="https://aioseo.com/seo-analyzer/">h</a></p>
</li>
<li><p><a target="_blank" href="https://aioseo.com/seo-analyzer/">A</a><a target="_blank" href="https://seomator.com/free-tools">h</a><a target="_blank" href="https://www.seoptimer.com/">refs</a></p>
</li>
</ol>
<h1 id="heading-nextjs-seo">Next.js SEO</h1>
<p>Next.js is a popular React-based web framework that has gained popularity and a growing community in recent years. It’s a powerful tool for building fast and SEO-friendly web applications with dynamic pages that work great on mobile devices.</p>
<p>Due to the complex nature of isomorphic system design, Next.js SEO can be a tricky topic to get your head around. You are coming from traditional React apps, and you’re relying solely on documentation.</p>
<p>With its built-in support for server-side rendering, static site generation, and now React server components, Next.js provides a robust platform for achieving quality SEO web traffic in your web application. It also helps you deliver exceptional user experiences across multiple pages in Node and React apps while making them SEO-friendly.</p>
<h2 id="heading-how-is-next-seo-different-from-other-frameworks">How is Next SEO different from other Frameworks?</h2>
<p>Next.js SEO sets itself apart by streamlining so many features and free tools into a well-organized package that you can easily digest and apply in your single applications. Nextjs does a great job when it comes to tasks such as search engine optimization, image optimization, and minimizing cumulative layout shift.</p>
<p>Nextjs SEo won’t change much conceptually. If you are looking for good search engine results and organic traffic, the game still revolves around the notion of fast page loads, quick paints, low cumulative layout shifts, and all the rest. Static pages still play a large role as well.</p>
<p>But Next.js gives us some pretty cool and novel features that help facilitate excellent search engine metrics, and it’s more than just React Server Components.</p>
<h2 id="heading-best-practices-for-higher-rankings">Best Practices for Higher Rankings</h2>
<p>In addition to leveraging Next.js features for SEO, there are several other Next.js best practices you should consider to optimize your site’s visibility to search engines. Here are key strategies, including your mention of robots or sitemaps:</p>
<ul>
<li><p><strong>Robots.txt</strong>: This is a text file placed in the root directory of your site that tells search engine crawlers which pages or sections of your site should not be crawled or indexed. For a Next.js site, you can create a <code>robots.txt</code> file and serve it statically. Ensure it’s accessible by placing it in the <code>public</code> folder. This will help control the crawler traffic to your site, prevent the indexing of certain pages, and help manage the crawl budget.</p>
</li>
<li><p><strong>XML Sitemaps</strong>: A sitemap is crucial as it lists all URLs for a site, allowing search engines to crawl the site more intelligently. In Next.js, you can generate sitemaps dynamically during your build process. Static generation is often preferred for performance reasons. You can use libraries like <code>next-sitemap</code> Automate the generation of sitemaps during your build process.</p>
</li>
<li><p><strong>Use Semantic HTML</strong>: Semantic HTML5 elements (like <code>&lt;header&gt;</code>, <code>&lt;footer&gt;</code>, <code>&lt;article&gt;</code>, and <code>&lt;section&gt;</code>) help search engines understand the structure of your website and the performance of the content within each section. This can be particularly beneficial for SEO.</p>
</li>
<li><p><strong>Optimize Page Speed:</strong> Google considers page speed as the ranking factor. Optimize images, leverage efficient CSS and Javascript, use Nextjs’s Image component for optimized image handling, and consider implementing a Content Delivery Network (CDN) to serve your content faster.</p>
</li>
<li><p><strong>Meta Tags and Descriptions:</strong> Ensure each page has a unique title and description meta tags that accurately describe the page content. These are crucial for SEO as they appear in search engine results.</p>
</li>
<li><p><strong>Structured Data:</strong> Implement structured data using JSON-LD to help search engines understand the content of your pages and provide rich results. Next.js can handle inline scripts where you can place your JSON-LD structured data.</p>
</li>
<li><p><strong>Accessibility (A11y)</strong>: Making your website accessible is not only a good practice for usability, It also impacts SEO. Ensuring your website is accessible to all users, including those with disabilities, can positively influence your rankings.</p>
</li>
<li><p><strong>Mobile-Friendliness</strong>: With the increasing use of mobile devices, having a mobile-friendly website is crucial. Next.js’s responsive design capabilities can help ensure that your website looks good on all devices, which is important for both user experience and SEO.</p>
</li>
<li><p><strong>Content Quality:</strong> Regularly update your website with high-quality, relevant content that addresses your audience’s needs. This is vital for SEO and helps retain visitors.</p>
</li>
</ul>
<p>Implementing these practices within your Next.js application can significantly enhance your SEO performance and ensure your site is well-optimized for search engines.</p>
<h2 id="heading-effective-meta-tag-integration-in-next13">Effective Meta Tag Integration in Next13</h2>
<p>Next.js 13 has completely overhauled the process of integrating meta tags, bringing about significant changes.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Explore the procedure for configuring <a target="_self" href="https://nextjs.org/learn-pages-router/basics/assets-metadata-css/metadata">metadata</a> in Next Js 12 or earlier.</div>
</div>

<p>In the most recent iteration of Next.js, there are two approaches to configuring meta tags. You can utilize either the <code>generateMetadata</code> method or incorporate a static <code>metadata</code> object within the <code>layout.tsx</code> or <code>page.tsx</code> files.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Refer to the <a target="_self" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#metadata-fields">metadata fields</a> to access the comprehensive list of supported options with Next JS 13 and above.</div>
</div>

<h3 id="heading-the-static-metadata-objecthttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadatathe-metadata-object"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#the-metadata-object">The Static Metadata Object</a></h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx or page.tsx</span>

<span class="hljs-keyword">import</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>

<span class="hljs-comment">// either Static metadata</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
  <span class="hljs-attr">title</span>: <span class="hljs-string">'Create Next App'</span>,
  <span class="hljs-attr">description</span>: <span class="hljs-string">'Generated by create next app'</span>,
  <span class="hljs-attr">icons</span>: {
    <span class="hljs-attr">icon</span>: <span class="hljs-string">"https://nextjs.org/favicon.ico"</span>
  }
}


<span class="hljs-comment">// &lt;head&gt; output</span>
&lt;title&gt;Create Next App&lt;/title&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Generated by create next app"</span>/&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://nextjs.org/favicon.ico"</span>/&gt;</span></span>
</code></pre>
<h3 id="heading-the-generatemetadatafunctionhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadatageneratemetadata-function"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#generatemetadata-function">The generateMetadataFunction</a></h3>
<p>Utilizing the <code>generateMetadata</code> functionality allows for the execution of API calls. Additionally, access to parameters such as <code>params</code>, <code>searchParams</code>, and <code>parent</code> provides the means to generate dynamic metadata for dynamic routes.</p>
<p>The <code>generateMetadata</code> function is expected to return a Metadata object encompassing one or more metadata fields.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx or page.tsx</span>
<span class="hljs-keyword">import</span> { Metadata, ResolvingMetadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>

type Props = {
  <span class="hljs-attr">params</span>: { <span class="hljs-attr">id</span>: string }
  <span class="hljs-attr">searchParams</span>: { [key: string]: string | string[] | <span class="hljs-literal">undefined</span> }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateMetadata</span>(<span class="hljs-params">
  { params, searchParams }: Props,
  parent: ResolvingMetadata
</span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">Metadata</span>&gt; </span>{

  <span class="hljs-comment">// read route params</span>
  <span class="hljs-keyword">const</span> id = params.id

  <span class="hljs-comment">// fetch data</span>
  <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://.../<span class="hljs-subst">${id}</span>`</span>).then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json())

  <span class="hljs-comment">// optionally access and extend (rather than replace) parent metadata</span>
  <span class="hljs-keyword">const</span> previousImages = (<span class="hljs-keyword">await</span> parent).openGraph?.images || []

  <span class="hljs-comment">// returning metadata object</span>
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">title</span>: product.title, <span class="hljs-comment">// Create Next App</span>
    <span class="hljs-attr">description</span>: product.description <span class="hljs-comment">//Generated by create next app</span>
    <span class="hljs-attr">icons</span>: {
      <span class="hljs-attr">icon</span>: <span class="hljs-string">"https://nextjs.org/favicon.ico"</span>
    },
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params">{ params, searchParams }: Props</span>) </span>{}
</code></pre>
<p><strong>Following will be the &lt;head&gt; Output</strong></p>
<pre><code class="lang-javascript">&lt;title&gt;Create Next App&lt;/title&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Generated by create next app"</span>/&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://nextjs.org/favicon.ico"</span>/&gt;</span></span>
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><em>The </em><code>metadata</code><em> object and </em><code>generateMetadata</code><em> function exports are only supported in Server Components. You cannot export both the </em><code>metadata</code><em> object and </em><code>generateMetadata</code><em> function from the same route segment.</em></div>
</div>

<p><strong>Next.js</strong> will automatically include some crucial meta tags by default.</p>
<pre><code class="lang-javascript">&lt;!-- <span class="hljs-keyword">default</span> metatags added by Next JS framework --&gt;
<span class="xml"><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>
<span class="xml"><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"</span>/&gt;</span></span>
</code></pre>
<p>So far, we have progressed. Now, let us examine all metadata fields and their various options.</p>
<h3 id="heading-viewport-metadata-objecthttpsnextjsorgdocsappapi-referencefunctionsgenerate-viewport"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-viewport">viewport MetaData Object</a></h3>
<p>However, viewport options can be superseded by exporting a <code>viewport</code> object from either the <code>layout.tsx</code> or <code>page.tsx</code> files.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx or page.tsx</span>
<span class="hljs-keyword">import</span> type { Viewport } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>

<span class="hljs-comment">// static viewport object</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> viewport: Viewport = {
    <span class="hljs-attr">width</span>: <span class="hljs-string">'device-width'</span>,
    <span class="hljs-attr">initialScale</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">maximumScale</span>: <span class="hljs-number">5</span>,
    <span class="hljs-attr">minimumScale</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">themeColor</span>: [
      { <span class="hljs-attr">media</span>: <span class="hljs-string">'(prefers-color-scheme: light)'</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">'cyan'</span> },
      { <span class="hljs-attr">media</span>: <span class="hljs-string">'(prefers-color-scheme: dark)'</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">'black'</span> },
    ],
    <span class="hljs-attr">colorScheme</span>: <span class="hljs-string">'dark'</span>,
};

<span class="hljs-comment">//&lt;head&gt; ouput</span>
<span class="xml"><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, minimum-scale=1, maximum-scale=5"</span>/&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"theme-color"</span> <span class="hljs-attr">media</span>=<span class="hljs-string">"(prefers-color-scheme: light)"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"cyan"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"theme-color"</span> <span class="hljs-attr">media</span>=<span class="hljs-string">"(prefers-color-scheme: dark)"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"black"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"color-scheme"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"dark"</span> /&gt;</span></span>
</code></pre>
<p>The viewport object can also be dynamically generated using the asynchronous function <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-viewport"><code>generateViewport</code></a>. This operates similarly to the <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata"><code>generateMetadata</code></a> function.</p>
<p><strong><em>Good to know:</em></strong> <em>If the viewport doesn’t depend on runtime information, it should be defined using the static</em> <code>viewport</code> <em>object rather than</em> <code>generateMetadata</code><em>.</em></p>
<h3 id="heading-template-objecthttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadatatemplate-object"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#template-object">Template Object</a></h3>
<p>A template object can be used to define default or fallback values. This can be only defined in layout.tsx.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
  <span class="hljs-attr">title</span>: {
    <span class="hljs-attr">template</span>: <span class="hljs-string">'...'</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-string">'...'</span>,
    <span class="hljs-attr">absolute</span>: <span class="hljs-string">'...'</span>,
  },
}
</code></pre>
<p>1. <code>title.default</code> can be used to provide a fallback title to child route segments that don't define a <code>title</code>.</p>
<p>2. <code>title.template</code>can be used to add a prefix or a suffix to <code>titles</code> defined in child route segments.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// app/layout.tsx</span>
<span class="hljs-keyword">import</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
  <span class="hljs-attr">title</span>: {
    <span class="hljs-attr">template</span>: <span class="hljs-string">'%s | Acme'</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-string">'Acme'</span>, <span class="hljs-comment">// a default is required when creating a template</span>
  },
}


<span class="hljs-comment">// app/page.tsx</span>
<span class="hljs-keyword">import</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
  <span class="hljs-attr">title</span>: <span class="hljs-string">'About'</span>,
}

<span class="hljs-comment">// Output: &lt;title&gt;About | Acme&lt;/title&gt;</span>
</code></pre>
<p>3. <code>title.absolute</code>can be used to provide a title that ignores <code>title.template</code> set in parent segments.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx</span>
<span class="hljs-keyword">import</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
  <span class="hljs-attr">title</span>: {
    <span class="hljs-attr">template</span>: <span class="hljs-string">'%s | Acme'</span>,
  },
}

<span class="hljs-comment">// app/page.tsx</span>
<span class="hljs-keyword">import</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
  <span class="hljs-attr">title</span>: {
    <span class="hljs-attr">absolute</span>: <span class="hljs-string">'About'</span>,
  },
}

<span class="hljs-comment">// Output: &lt;title&gt;About&lt;/title&gt;</span>
</code></pre>
<h3 id="heading-basic-fieldshttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadatabasic-fields"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#basic-fields">Basic Fields</a></h3>
<p>Let’s check all basic fields which is required for SEO.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">generator</span>: <span class="hljs-string">'Next.js'</span>,
  <span class="hljs-attr">applicationName</span>: <span class="hljs-string">'Next.js'</span>,
  <span class="hljs-attr">referrer</span>: <span class="hljs-string">'origin-when-cross-origin'</span>,
  <span class="hljs-attr">keywords</span>: [<span class="hljs-string">'Next.js'</span>, <span class="hljs-string">'React'</span>, <span class="hljs-string">'JavaScript'</span>],
  <span class="hljs-attr">authors</span>: [{ <span class="hljs-attr">name</span>: <span class="hljs-string">'Seb'</span> }, { <span class="hljs-attr">name</span>: <span class="hljs-string">'Josh'</span>, <span class="hljs-attr">url</span>: <span class="hljs-string">'https://nextjs.org'</span> }],
  <span class="hljs-attr">creator</span>: <span class="hljs-string">'Jiachi Liu'</span>,
  <span class="hljs-attr">publisher</span>: <span class="hljs-string">'Sebastian Markbåge'</span>
}

<span class="hljs-comment">// Head output</span>
&lt;meta name=<span class="hljs-string">"application-name"</span> content=<span class="hljs-string">"Next.js"</span> /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"author"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Seb"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"author"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://nextjs.org"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"author"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Josh"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"generator"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Next.js"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"keywords"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Next.js,React,JavaScript"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"referrer"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"origin-when-cross-origin"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"color-scheme"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"dark"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"creator"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Jiachi Liu"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"publisher"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Sebastian Markbåge"</span> /&gt;</span></span>
</code></pre>
<h3 id="heading-formatedetection-field">FormateDetection Field</h3>
<p>The behaviour of these automatic links for phone numbers, email addresses, and physical addresses can be controlled through the utilisation of <code>formatDetection</code>.</p>
<p>Please refer to the example below, which illustrates the disabling of the automatic link behaviour for phone numbers, email addresses, and telephone contacts.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">formatDetection</span>: {
    <span class="hljs-attr">email</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">address</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">telephone</span>: <span class="hljs-literal">false</span>,
  },
}

<span class="hljs-comment">// Head output</span>
&lt;meta name=<span class="hljs-string">"format-detection"</span> content=<span class="hljs-string">"telephone=no, address=no, email=no"</span> /&gt;
</code></pre>
<h3 id="heading-metadatabase-fieldhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadatametadatabase"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#metadatabase">metadataBase Field</a></h3>
<p>The <code>metadataBase</code> option provides a convenient way to establish a base URL prefix for metadata fields that demand a fully qualified URL.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">metadataBase</span>: <span class="hljs-keyword">new</span> URL(<span class="hljs-string">'https://acme.com'</span>),
  <span class="hljs-attr">alternates</span>: {
    <span class="hljs-attr">canonical</span>: <span class="hljs-string">'/'</span>,
    <span class="hljs-attr">languages</span>: {
      <span class="hljs-string">'en-US'</span>: <span class="hljs-string">'/en-US'</span>,
      <span class="hljs-string">'de-DE'</span>: <span class="hljs-string">'/de-DE'</span>,
    },
  },
  <span class="hljs-attr">openGraph</span>: {
    <span class="hljs-attr">images</span>: <span class="hljs-string">'/og-image.png'</span>,
  },
}


<span class="hljs-comment">// &lt;head&gt; out will be</span>
&lt;link rel=<span class="hljs-string">"canonical"</span> href=<span class="hljs-string">"https://acme.com"</span> /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"alternate"</span> <span class="hljs-attr">hreflang</span>=<span class="hljs-string">"en-US"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://acme.com/en-US"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"alternate"</span> <span class="hljs-attr">hreflang</span>=<span class="hljs-string">"de-DE"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://acme.com/de-DE"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://acme.com/og-image.png"</span> /&gt;</span></span>
</code></pre>
<p>In the preceding example, you’ll observe that the <code>metadataBase</code> includes the base URL. Nevertheless, in other instances, such as <code>canonical</code> and <code>openGraph</code>, the base URL is not explicitly defined. Despite this, the output reflects the presence of the base URL.</p>
<h3 id="heading-opengraph-fieldhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadataopengraph"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#opengraph">openGraph Field</a></h3>
<p>The <code>openGraph</code> field is employed for incorporating <code>og:*</code> related meta tags. Let us now review all the available options under this category.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx or page.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">openGraph</span>: {
    <span class="hljs-attr">title</span>: <span class="hljs-string">'Next.js'</span>,
    <span class="hljs-attr">description</span>: <span class="hljs-string">'The React Framework for the Web'</span>,
    <span class="hljs-attr">url</span>: <span class="hljs-string">'https://nextjs.org'</span>,
    <span class="hljs-attr">siteName</span>: <span class="hljs-string">'Next.js'</span>,
    <span class="hljs-attr">images</span>: [
      {
        <span class="hljs-attr">url</span>: <span class="hljs-string">'https://nextjs.org/og.png'</span>,
        <span class="hljs-attr">width</span>: <span class="hljs-number">800</span>,
        <span class="hljs-attr">height</span>: <span class="hljs-number">600</span>,
      },
      {
        <span class="hljs-attr">url</span>: <span class="hljs-string">'https://nextjs.org/og-alt.png'</span>,
        <span class="hljs-attr">width</span>: <span class="hljs-number">1800</span>,
        <span class="hljs-attr">height</span>: <span class="hljs-number">1600</span>,
        <span class="hljs-attr">alt</span>: <span class="hljs-string">'My custom alt'</span>,
      },
    ],
    <span class="hljs-attr">locale</span>: <span class="hljs-string">'en_US'</span>,
    <span class="hljs-attr">type</span>: <span class="hljs-string">'article'</span>, <span class="hljs-comment">// this can be 'website' as well</span>
    <span class="hljs-attr">publishedTime</span>: <span class="hljs-string">'2023-01-01T00:00:00.000Z'</span>,
    <span class="hljs-attr">authors</span>: [<span class="hljs-string">'Seb'</span>, <span class="hljs-string">'Josh'</span>],
  },
}

<span class="hljs-comment">// Head output</span>
&lt;meta property=<span class="hljs-string">"og:title"</span> content=<span class="hljs-string">"Next.js"</span> /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"The React Framework for the Web"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:url"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://nextjs.org/"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:site_name"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Next.js"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:locale"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"en_US"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:url"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://nextjs.org/og.png"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:width"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"800"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:height"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"600"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:url"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://nextjs.org/og-alt.png"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:width"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"1800"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:height"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"1600"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image:alt"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"My custom alt"</span> /&gt;</span></span>
<span class="hljs-comment">// &lt;meta property="og:type" content="website" /&gt;</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:type"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"article"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"article:published_time"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"2023-01-01T00:00:00.000Z"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"article:author"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Seb"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"article:author"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Josh"</span> /&gt;</span></span>
</code></pre>
<h3 id="heading-robotsfieldhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadatarobots"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#robots">robotsField</a></h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> type { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'next'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
  <span class="hljs-attr">robots</span>: {
    <span class="hljs-attr">index</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">follow</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">nocache</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">googleBot</span>: {
      <span class="hljs-attr">index</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">follow</span>: <span class="hljs-literal">false</span>,
      <span class="hljs-attr">noimageindex</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-string">'max-video-preview'</span>: <span class="hljs-number">-1</span>,
      <span class="hljs-string">'max-image-preview'</span>: <span class="hljs-string">'large'</span>,
      <span class="hljs-string">'max-snippet'</span>: <span class="hljs-number">-1</span>,
    },
  },
}

<span class="hljs-comment">// Head ouput</span>
&lt;meta name=<span class="hljs-string">"robots"</span> content=<span class="hljs-string">"noindex, follow, nocache"</span> /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span>
  <span class="hljs-attr">name</span>=<span class="hljs-string">"googlebot"</span>
  <span class="hljs-attr">content</span>=<span class="hljs-string">"index, nofollow, noimageindex, max-video-preview:-1, max-image-preview:large, max-snippet:-1"</span>
/&gt;</span></span>
</code></pre>
<h3 id="heading-icons-fieldhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadataicons"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#icons">icons Field</a></h3>
<p>Next.js recommends using the <a target="_blank" href="https://nextjs.org/docs/app/api-reference/file-conventions/metadata/app-icons#image-files-ico-jpg-png">file-based Metadata API</a> for icons where possible. Rather than having to sync the config export with actual files, the file-based API will automatically generate the correct metadata for you.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">icons</span>: {
    <span class="hljs-attr">icon</span>: <span class="hljs-string">'/icon.png'</span>,
    <span class="hljs-attr">shortcut</span>: <span class="hljs-string">'/shortcut-icon.png'</span>,
    <span class="hljs-attr">apple</span>: <span class="hljs-string">'/apple-icon.png'</span>,
    <span class="hljs-attr">other</span>: {
      <span class="hljs-attr">rel</span>: <span class="hljs-string">'apple-touch-icon-precomposed'</span>,
      <span class="hljs-attr">url</span>: <span class="hljs-string">'/apple-touch-icon-precomposed.png'</span>,
    },
  },
}

<span class="hljs-comment">// Head Output</span>
&lt;link rel=<span class="hljs-string">"shortcut icon"</span> href=<span class="hljs-string">"/shortcut-icon.png"</span> /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/icon.png"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"apple-touch-icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/apple-icon.png"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span>
  <span class="hljs-attr">rel</span>=<span class="hljs-string">"apple-touch-icon-precomposed"</span>
  <span class="hljs-attr">href</span>=<span class="hljs-string">"/apple-touch-icon-precomposed.png"</span>
/&gt;</span></span>
</code></pre>
<h3 id="heading-manifest-fieldhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadatamanifest"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#manifest">manifest Field</a></h3>
<p>A web application manifest, defined in the <a target="_blank" href="https://w3c.github.io/manifest/">Web Application Manifest</a> specification, is a <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/JSON">JSON</a> text file that provides information about a web application.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">manifest</span>: <span class="hljs-string">'https://nextjs.org/manifest.json'</span>,
}

<span class="hljs-comment">// Head Output</span>
&lt;link rel=<span class="hljs-string">"manifest"</span> href=<span class="hljs-string">"https://nextjs.org/manifest.json"</span> /&gt;
</code></pre>
<h3 id="heading-twitter-fieldhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadatatwitter"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#twitter">twitter Field</a></h3>
<p>The Twitter metadata specification is utilized by Twitter to present rich text, imagery, and video content when links are shared on the platform.</p>
<p>Learn more about the <a target="_blank" href="https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/markup">Twitter Card markup reference.</a></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx or page.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">twitter</span>: {
    <span class="hljs-attr">card</span>: <span class="hljs-string">'app'</span>,
    <span class="hljs-attr">title</span>: <span class="hljs-string">'Next.js'</span>,
    <span class="hljs-attr">description</span>: <span class="hljs-string">'The React Framework for the Web'</span>,
    <span class="hljs-attr">siteId</span>: <span class="hljs-string">'1467726470533754880'</span>,
    <span class="hljs-attr">creator</span>: <span class="hljs-string">'@nextjs'</span>,
    <span class="hljs-attr">creatorId</span>: <span class="hljs-string">'1467726470533754880'</span>,
    <span class="hljs-attr">images</span>: {
      <span class="hljs-attr">url</span>: <span class="hljs-string">'https://nextjs.org/og.png'</span>,
      <span class="hljs-attr">alt</span>: <span class="hljs-string">'Next.js Logo'</span>,
    },
    <span class="hljs-attr">app</span>: {
      <span class="hljs-attr">name</span>: <span class="hljs-string">'twitter_app'</span>,
      <span class="hljs-attr">id</span>: {
        <span class="hljs-attr">iphone</span>: <span class="hljs-string">'twitter_app://iphone'</span>,
        <span class="hljs-attr">ipad</span>: <span class="hljs-string">'twitter_app://ipad'</span>,
        <span class="hljs-attr">googleplay</span>: <span class="hljs-string">'twitter_app://googleplay'</span>,
      },
      <span class="hljs-attr">url</span>: {
        <span class="hljs-attr">iphone</span>: <span class="hljs-string">'https://iphone_url'</span>,
        <span class="hljs-attr">ipad</span>: <span class="hljs-string">'https://ipad_url'</span>,
      },
    },
  },
}


<span class="hljs-comment">// Head Output</span>
&lt;meta name=<span class="hljs-string">"twitter:site:id"</span> content=<span class="hljs-string">"1467726470533754880"</span> /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:creator"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"@nextjs"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:creator:id"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"1467726470533754880"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:title"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Next.js"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"The React Framework for the Web"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:card"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"app"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:image"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://nextjs.org/og.png"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:image:alt"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Next.js Logo"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:app:name:iphone"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"twitter_app"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:app:id:iphone"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"twitter_app://iphone"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:app:id:ipad"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"twitter_app://ipad"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:app:id:googleplay"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"twitter_app://googleplay"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:app:url:iphone"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://iphone_url"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:app:url:ipad"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://ipad_url"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:app:name:ipad"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"twitter_app"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:app:name:googleplay"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"twitter_app"</span> /&gt;</span></span>
</code></pre>
<h3 id="heading-verification-fieldhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadataverification"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#verification">verification Field</a></h3>
<p><code>verification</code> field is used to add different search engine verification code to verify site.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx or page.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">verification</span>: {
    <span class="hljs-attr">google</span>: <span class="hljs-string">'google'</span>,
    <span class="hljs-attr">yandex</span>: <span class="hljs-string">'yandex'</span>,
    <span class="hljs-attr">yahoo</span>: <span class="hljs-string">'yahoo'</span>,
    <span class="hljs-attr">other</span>: {
      <span class="hljs-attr">me</span>: [<span class="hljs-string">'my-email'</span>, <span class="hljs-string">'my-link'</span>],
    },
  },
}

<span class="hljs-comment">// Head Output</span>
&lt;meta name=<span class="hljs-string">"google-site-verification"</span> content=<span class="hljs-string">"google"</span> /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"y_key"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"yahoo"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"yandex-verification"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"yandex"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"me"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"my-email"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"me"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"my-link"</span> /&gt;</span></span>
</code></pre>
<h3 id="heading-alternates-fieldhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadataalternates"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#alternates">alternates Field</a></h3>
<p><code>alternates</code> field is used to create meta tags for <code>canonical</code>, <code>languages</code>, <code>media</code> and define <code>type</code> of page.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx or page.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">alternates</span>: {
    <span class="hljs-attr">canonical</span>: <span class="hljs-string">'https://nextjs.org'</span>,
    <span class="hljs-attr">languages</span>: {
      <span class="hljs-string">'en-US'</span>: <span class="hljs-string">'https://nextjs.org/en-US'</span>,
      <span class="hljs-string">'de-DE'</span>: <span class="hljs-string">'https://nextjs.org/de-DE'</span>,
    },
    <span class="hljs-attr">media</span>: {
      <span class="hljs-string">'only screen and (max-width: 600px)'</span>: <span class="hljs-string">'https://nextjs.org/mobile'</span>,
    },
    <span class="hljs-attr">types</span>: {
      <span class="hljs-string">'application/rss+xml'</span>: <span class="hljs-string">'https://nextjs.org/rss'</span>,
    },
  },
}

<span class="hljs-comment">// Head Output</span>
&lt;link rel=<span class="hljs-string">"canonical"</span> href=<span class="hljs-string">"https://nextjs.org"</span> /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"alternate"</span> <span class="hljs-attr">hreflang</span>=<span class="hljs-string">"en-US"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://nextjs.org/en-US"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"alternate"</span> <span class="hljs-attr">hreflang</span>=<span class="hljs-string">"de-DE"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://nextjs.org/de-DE"</span> /&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span>
  <span class="hljs-attr">rel</span>=<span class="hljs-string">"alternate"</span>
  <span class="hljs-attr">media</span>=<span class="hljs-string">"only screen and (max-width: 600px)"</span>
  <span class="hljs-attr">href</span>=<span class="hljs-string">"https://nextjs.org/mobile"</span>
/&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span>
  <span class="hljs-attr">rel</span>=<span class="hljs-string">"alternate"</span>
  <span class="hljs-attr">type</span>=<span class="hljs-string">"application/rss+xml"</span>
  <span class="hljs-attr">href</span>=<span class="hljs-string">"https://nextjs.org/rss"</span>
/&gt;</span></span>
</code></pre>
<h3 id="heading-other-fieldhttpsnextjsorgdocsappapi-referencefunctionsgenerate-metadataother"><a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#other">other Field</a></h3>
<p>All metadata options should be covered using the built-in support. However, there may be custom metadata tags specific to your site or brand-new metadata tags just released. You can use the <code>other</code> option to render any custom metadata tag.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx or page.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">other</span>: {
    <span class="hljs-attr">custom</span>: <span class="hljs-string">'meta'</span>,
  },
}

<span class="hljs-comment">// Head Output</span>
&lt;meta name=<span class="hljs-string">"custom"</span> content=<span class="hljs-string">"meta"</span> /&gt;
</code></pre>
<p>To generate multiple same-key meta tags, you can use an array value.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// layout.tsx or page.tsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  <span class="hljs-attr">other</span>: {
    <span class="hljs-attr">custom</span>: [<span class="hljs-string">'meta1'</span>, <span class="hljs-string">'meta2'</span>],
  },
}

<span class="hljs-comment">// Head Output</span>
&lt;meta name=<span class="hljs-string">"custom"</span> content=<span class="hljs-string">"meta1"</span> /&gt; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"custom"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"meta2"</span> /&gt;</span></span>
</code></pre>
<p>There are so many other options available like <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#applewebapp"><code>appleWebApp</code></a>, <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#applinks"><code>appLinks</code></a>, <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#archives"><code>archives</code></a>, <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#assets"><code>assets</code></a>, <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#bookmarks"><code>bookmarks</code></a>, <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#category"><code>category</code></a>. Refer to the <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#metadata-fields">Metadata Fields</a> to access all lists of supported options with Next JS 13 and above.</p>
<p>There are few unsupported Metadata. Refer to the <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/generate-metadata#unsupported-metadata"><strong>Unsupported MetaData</strong></a> to know more about them.</p>
<h3 id="heading-should-a-url-end-with-a-trailing-slash-whats-the-difference">Should a URL end with a Trailing Slash “/“? What’s the difference?</h3>
<p>Whether a URL ends with a trailing slash primarily affects how the server interprets the request and how relative paths are resolved.</p>
<p>The specific differences are as follows:</p>
<ol>
<li><strong>Fundamental Concepts</strong></li>
</ol>
<p><strong>URL (Uniform Resource Locator):</strong></p>
<p>A unique identifier for resources on the internet, such as web pages, images, APIs, etc.</p>
<p><strong>Directory vs. Resource:</strong></p>
<p>A URL ending with a <code>/</code> typically represents a <strong>directory</strong>. For example:</p>
<pre><code class="lang-typescript">https:<span class="hljs-comment">//example.com/folder/</span>
</code></pre>
<p>A URL <em>not</em> ending with a <code>/</code> usually points to a specific <strong>resource</strong> (like a file). For example:</p>
<pre><code class="lang-typescript">https:<span class="hljs-comment">//example.com/file</span>
</code></pre>
<ol start="2">
<li><strong>Specific Differences Between With and Without a “/“</strong></li>
</ol>
<p><strong>(1) Directory vs. Resource</strong></p>
<ul>
<li><a target="_blank" href="https://example.com/folder/">https://example.com/folder/</a></li>
</ul>
<blockquote>
<p><em>A server will typically interpret this as a directory and attempt to return the default file within that directory (e.g., index.html).</em></p>
</blockquote>
<ul>
<li><a target="_blank" href="https://example.com/folder">https://example.com/folder</a></li>
</ul>
<blockquote>
<p><em>A server might treat this as a file. If folder is actually a directory and not a file, the server will often issue a 301 redirect to folder/.</em></p>
</blockquote>
<p>📌 Example:</p>
<ul>
<li>When you visit <a target="_blank" href="https://example.com/blog/"><code>https://example.com/blog/</code></a></li>
</ul>
<blockquote>
<p><em>the server might directly serve the content of</em> <a target="_blank" href="https://example.com/blog/index.html."><code>https://example.com/blog/index.html</code></a></p>
</blockquote>
<ul>
<li>When you visit <code>https://example.com/blog</code> (and <code>blog</code> is a directory),</li>
</ul>
<blockquote>
<p><em>the server will likely first redirect you to</em> <code>https://example.com/blog/</code> and then serve <code>index.html</code>.</p>
</blockquote>
<p><strong>(2) Relative Path Resolution</strong></p>
<p>The presence of a trailing slash affects how relative paths are resolved.</p>
<p>Assume an HTML page contains the following <code>&lt;img&gt;</code> tag:</p>
<pre><code class="lang-typescript">&lt;img src=<span class="hljs-string">"image.png"</span>&gt;
</code></pre>
<p>📌 Example:</p>
<ul>
<li>If the page is loaded from <code>https://example.com/folder/</code>,</li>
</ul>
<blockquote>
<p><em>the image path will be resolved to</em> <a target="_blank" href="https://example.com/folder/image.png."><code>https://example.com/folder/image.png</code>.</a></p>
</blockquote>
<ul>
<li>If the page is loaded from <code>https://example.com/folder</code>,</li>
</ul>
<blockquote>
<p><em>the image path will be resolved to</em> <code>https://example.com/image.png</code>. This could lead to a <strong>404 Not Found</strong> error because the browser <mark>incorrectly</mark> looks for <code>image.png</code> in the root directory (<code>example.com/</code>) instead of inside <code>folder/</code>.</p>
</blockquote>
<p><strong>Reasoning:</strong></p>
<ul>
<li><p>For a URL ending in <code>/</code>, the browser treats it as a directory, and relative paths are resolved based on that directory (<code>folder/</code>).</p>
</li>
<li><p>Without the <code>/</code>, the browser may assume <code>folder</code> is a file, causing errors in resolving relative paths.</p>
</li>
</ul>
<p><strong>(3) SEO Impact</strong></p>
<p>Search engines may treat <code>https://example.com/folder/</code> and <code>https://example.com/folder</code> as two different pages. This can lead to <strong>duplicate content issues</strong>, which can negatively affect your SEO rankings. Therefore:</p>
<ul>
<li><p>It is best practice for a website to <strong>choose one canonical form</strong> and use <strong>301 redirects</strong> to enforce it.</p>
</li>
<li><p>For example, automatically redirect all requests for <code>https://example.com/folder</code> to <code>https://example.com/folder/</code>, or vice versa.</p>
</li>
</ul>
<p><strong>(4) API Requests</strong></p>
<p>For RESTful APIs, the presence or absence of a trailing slash can lead to different behaviors:</p>
<ul>
<li><p><code>https://api.example.com/users</code> might return a list of all users.</p>
</li>
<li><p><code>https://api.example.com/users/</code> might return a 404 error or produce a different result, depending on the server's implementation.</p>
</li>
</ul>
<p>Some API servers are very sensitive to the trailing slash, so it is crucial to follow the specifications in the API documentation.</p>
<ol start="3">
<li><strong>Summary</strong></li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751880135880/b6e00741-5ad0-4f61-9048-e162695771b9.webp" alt class="image--center mx-auto" /></p>
<p>If you are developing a website, it is recommended to:</p>
<ol>
<li><p><strong>Standardize your URL structure.</strong> For example, enforce that all directory URLs end with a <code>/</code> (or that none do) and use 301 redirects to maintain consistency.</p>
</li>
<li><p><strong>Test your API’s behavior</strong> to confirm <mark>whether</mark> the presence of a trailing slash affects request outcomes.</p>
</li>
</ol>
<h1 id="heading-accessibility">Accessibility</h1>
<p>As a front-end developer, it is your responsibility to ensure that the websites you create are accessible to all users, including those with disabilities. In this guide, we will explore what web accessibility is, why it is important, and how you can create web-accessible websites.</p>
<h2 id="heading-what-is-web-accessibility">What is Web Accessibility?</h2>
<p>Before we dive into what web accessibility is, we should first understand what the word <strong>Accessibility</strong> entails:</p>
<p>From my knowledge, <strong>Accessibility</strong> means the ability of everyone regardless of their condition to have access to something (e.g. internet, transport, system).</p>
<p>Wikipedia says, “Accessibility refers to the design of products, devices, services, or environments for people who experience disabilities.“</p>
<p>So we could eventually say that Web Accessibility is a way to make everyone including the disabled to have access to the website and internet as a whole.</p>
<p>To put it differently, we could also say:</p>
<blockquote>
<p>Web Accessibility means that people with disabilities can use the Web.</p>
</blockquote>
<p>At the end of the day, we can conclude that people with disabilities can perceive, understand, navigate, and interact with the Web and that they can contribute to the Web. Web accessibility also benefits those with temporary or conditional disabilities which in some cases may be aging, slow internet connection, or broken arm.</p>
<h2 id="heading-what-is-disability-and-types">What is Disability and Types?</h2>
<p>It’s important to build sites that are inclusive and accessible to everyone. There are at least six key areas of disability you can optimize for: <strong>visual</strong>, <strong>hearing</strong>, <strong>mobility</strong>, <strong>cognition</strong>, <strong>speed</strong>, and <strong>neural</strong>. Many tools and resources can help here, even if you are totally new to web accessibility.</p>
<p><a target="_blank" href="https://www.who.int/teams/noncommunicable-diseases/sensory-functions-disability-and-rehabilitation/world-report-on-disability">Over one billion people</a> live with some form of disability.</p>
<p>To be accessible, sites need to work across multiple devices with varying screen sizes and different kinds of input, such as screen readers. Moreover, sites should be usable by the broadest of users, including those with disabilities.</p>
<p>Here are a few disabilities your users may have:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742291769038/c264fe5a-35e2-4666-8cc5-944d6b28a86d.png" alt class="image--center mx-auto" /></p>
<p><strong>Visual issues</strong> range from an inability to distinguish colors to no vision at all:</p>
<ul>
<li><p>Ensures text content meets a minimum <a target="_blank" href="http://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast">contrast ratio threshold</a>.</p>
</li>
<li><p>Avoid communicating information <a target="_blank" href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#visual-audio-contrast-without-color">using solely color</a> and ensure that all text is <a target="_blank" href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#visual-audio-contrast-scale">resizable</a>.</p>
</li>
<li><p>Ensures all user interface components can be used with assistive technologies such as screen readers, magnifiers, and braille displays. This entails ensuring that UI components are marked up such that accessibility APIs can programmatically determine the <em>role</em>, <em>state</em>, <em>value</em>, and <em>title</em> of any element.</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Tip</strong>: The element inspection feature in the browser displays a tooltip of CSS properties that includes a quick check for the color contrast ratio.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742295962558/9c4773a0-ec50-40f2-adc9-1b8f2cd88779.jpeg" alt class="image--center mx-auto" /></p>
<p>Some people live with low vision, they often find themself zooming in on sites, their DevTools, and the Terminal. While supporting Zoom is almost never at the top of developers' to-do lists, it can make a world of difference for people like them.</p>
<p>Hearing issues mean a user may have issues hearing sound emitted from a page.</p>
<ul>
<li><p>Provide <a target="_blank" href="http://www.w3.org/TR/WCAG20/#media-equiv-av-only-alt">text alternatives</a> for all content that is not strictly text.</p>
</li>
<li><p>Test that your UI components are still functional <a target="_blank" href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#content-structure-separation-understanding">without sound</a>.</p>
</li>
</ul>
<p><strong>Mobility issues</strong> can include the inability to operate a mouse, a keyboard, or a touch screen.</p>
<ul>
<li><p>Make the content of your UI components <a target="_blank" href="http://www.w3.org/TR/wai-aria-practices/#keyboard">functionally accessible from a keyboard</a> for any actions one would otherwise use the mouse for</p>
</li>
<li><p>Ensure pages are correctly marked up for assistive technologies — including screen readers, voice control software, and physical switch controls — which tend to use the same APIs.</p>
</li>
</ul>
<p><strong>Cognitive issues</strong> mean a user may require assistive technologies to help them with reading text, so it’s important to ensure text alternatives exist.</p>
<ul>
<li><p>Be mindful when using animations. Avoid video and animation that <a target="_blank" href="http://www.w3.org/TR/WCAG20/#time-limits">repeat</a> or flash, which can cause <a target="_blank" href="http://www.w3.org/TR/WCAG20/#seizure">issues</a> for some users.<br />  The <a target="_blank" href="https://web.dev/articles/prefers-reduced-motion#too_much_motion_in_real_life_and_on_the_web"><code>prefers-reduced-motion</code></a> CSS media query lets you limit animations and auto-playing videos for users who prefer reduced motion:</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">/*
  If the user expresses a preference for reduced motion, don't use animations on buttons.
  */</span>
  @media (prefers-reduced-motion: reduce) {
    button {
      <span class="hljs-attr">animation</span>: none;
    }
  }
</code></pre>
</li>
<li><p>Avoid interactions that are <a target="_blank" href="https://www.w3.org/WAI/WCAG21/Understanding/no-timing.html">timing-based</a>.</p>
</li>
</ul>
<p>This may seem like a lot of bases to cover, but we will work through the process of assessing and improving the accessibility of your UI components.</p>
<p>For extra visual support, the GOV.UK accessibility team has created a series of <a target="_blank" href="https://accessibility.blog.gov.uk/2016/09/02/dos-and-donts-on-designing-for-accessibility/">accessibility do and don'ts digital posters</a>, which you can use to share the best practices with your team.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742297735797/ab2fe67e-212e-4865-8823-997e84178cc8.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-why-web-accessibility-is-important">Why Web Accessibility is important?</h2>
<p>The Web and the Internet as a whole are increasingly important resources in many aspects of our lives, including education, employment, government, commerce, health care, creation, and more. Therefore, it is important that the Web be accessible to everyone to provide equal access and equal opportunity to people with disabilities. An accessible Web can help people with disabilities participate more actively in society.</p>
<p>Also, an accessible web is often one of the easiest ways to do business with many people with disabilities, for instance, people who can not read print material, people who have difficulty going to physical stores or malls, and others. Furthermore, what you do for accessibility overlaps with other best practices such as mobile web design, usability, and search engine optimization (SEO).</p>
<p>An accessible website provides many people with disabilities with access to information and interaction. The accessibility barriers to print, audio, and visual media can be much more easily overcome through Web technologies.</p>
<p>I suggest reading “<a target="_blank" href="https://www.w3.org/WAI/bcase/soc">Social Factors in Developing a Web Accessibility Business Case for Your Organization</a>” which shows how the web impacts the lives of people with disabilities and Web accessibility as an aspect of cooperate social responsibility.</p>
<p>Another important consideration for organizations is that Web accessibility is required by laws and policies in some cases. <a target="_blank" href="https://www.w3.org/WAI/policy-res">WAI Web Accessibility Policy Resources</a> links to resources for addressing legal and policy factors within organizations, including a list of relevant <a target="_blank" href="https://www.w3.org/WAI/Policy/">laws and policies around the world</a>.</p>
<h2 id="heading-measure-ui-components-accessibility">Measure UI component’s accessibility</h2>
<p>When editing your page’s UI component for accessibility, ask yourself:</p>
<ul>
<li><p><strong>Can you use your UI component with the keyboard only?</strong><br />  Does the component manage to focus and avoid focus traps? Can it respond to the appropriate keyboard events?</p>
</li>
<li><p><strong>Can you use your UI component with the screen reader?</strong></p>
<p>  Have you provided text alternatives for any information present visually? Have you added semantic information using ARIA?</p>
</li>
<li><p><strong>Can your UI component work without sound?</strong></p>
<p>  Turn off your speakers and go through your use cases.</p>
</li>
<li><p><strong>Can your UI component work without color?</strong></p>
<p>  Ensure your UI component can be used by someone who can't see colors. A helpful tool for simulating color blindness is a Chrome extension called <a target="_blank" href="https://chromewebstore.google.com/detail/colorblindly/floniaahmccleoclneebhhmnjgdfijgg">Colorblindly</a> (Try all four forms of color blindness simulation available). You may also be interested in the <a target="_blank" href="https://chromewebstore.google.com/detail/daltonize/obcnmdgpjakcffkcjnonpdlainhphpgh">Daltonize</a> extension, which is similarly useful.</p>
</li>
<li><p><strong>Can your UI component work with high-contrast mode enabled?</strong></p>
<p>  All modern operating systems support a high contrast mode. <a target="_blank" href="https://chrome.google.com/webstore/detail/high-contrast/djcfdncoelnlbldjfhinnjlhdjlikmph">High Contrast</a> is a Chrome extension that can help here.</p>
</li>
</ul>
<p>Standardized controls (such as <code>&lt;button&gt;</code> and <code>&lt;select&gt;</code>) have accessibility built into the browser. They are focusable using the Tab key; they respond to keyboard events (like the <code>Enter</code>, <code>Space</code>, and arrow keys); and they have semantic roles, states, and properties used by accessibility tools. Their default styling should also meet the accessibility requirements listed.</p>
<p>Custom UI components (with the exception of components that extend standard elements like <code>&lt;button&gt;</code>) don’t have any built-in capabilities, including accessibility, so you need to provide it. A good place to start when implementing accessibility is to compare your component to an analogous standard element (or a combination of several standard elements, depending on how complex your component is).</p>
<p>Most browser developer tools support inspecting the accessibility tree of a page. In Chrome DevTools, this is available in the <strong>Accessibility</strong> tab in the <strong>Element</strong> panels.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742299503488/2570d6b4-fbe4-415c-9c80-b2d992c8e219.png" alt class="image--center mx-auto" /></p>
<p>Firefox also has an <strong>Accessibility</strong> panel.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742299604187/e31f4af7-8c1d-48a7-8585-de76fdfda109.jpeg" alt class="image--center mx-auto" /></p>
<p>Safari exposes accessibility information in the <strong>Elements</strong> panel’s <strong>Node</strong> tab.</p>
<p>The following is a list of questions you can ask yourself when attempting to make your UI component more accessible.</p>
<h2 id="heading-how-to-make-the-web-accessible">How to Make the Web Accessible</h2>
<p>Making the web accessible depends on the developers building for the web. Making your website accessible to people with disabilities, will end up making it accessible to everyone.</p>
<h3 id="heading-use-tabindex">Use <code>tabindex</code></h3>
<p>You can add keyboard focus for elements and UI components with the <code>tabindex</code> attribute. Keyboard-only and assistive technology users need to be able to place keyboard focus on elements to interact with them.</p>
<p>Built-in interactive elements (like &lt;Button/&gt;) are implicitly focusable, so they don’t need a <code>tabindex</code>, attribute unless you need to change their position in the tab order.</p>
<p>There are 3 types of <code>tabindex</code> values:</p>
<ul>
<li><p><code>tabindex="0"</code> is the most common and places elements in the natural tab order (defined by the DOM order)</p>
</li>
<li><p>A <code>tabindex</code> value equal to -1 causes the element to be programmatically focusable, but not in the tab order.</p>
</li>
<li><p>A <code>tabindex</code> value greater than 0 places the element in the manual tab order. All elements in the page with the positive tabindex value are visited in numerical order, before elements in the natural tab order.</p>
</li>
</ul>
<p>Warning: As a general rule, avoid positive tabindexes. Disrupting the normal focus order may confuse and frustrate your users. It’s therefore likely to cause the failure of <a target="_blank" href="https://www.w3.org/TR/WCAG22/#focus-order">Success Criterion 2.4.3.</a></p>
<p>Find some use cases for <code>tabindex</code> in this article <a target="_blank" href="https://web.dev/articles/using-tabindex">Using tabindex</a>.</p>
<p>Ensure that focus is always visible, whether by using the default focus ring style or by applying a discernible custom focus style. Remember not to trap keyboard users - they should be able to move focus away from an element using only the keyboard.</p>
<h3 id="heading-use-autofocus">Use autofocus</h3>
<p>The HTML autofocus attribute lets an author specify that a particular element should automatically take focus when the page is loaded. autofocus is already supported on all web form controls, including buttons. To autofocus elements in your own custom UI components, call the focus() method, supported on all HTML elements that can be focused (for example, <code>document.querySelector('myButton').focus()</code>).</p>
<h3 id="heading-add-keyboard-interaction">Add keyboard interaction</h3>
<p>Once your UI component is focusable, provide a good keyboard interaction story when a component is focused by handling appropriate keyboard events. For example, allow the user to use arrow keys to select menu options and <code>Space</code> or <code>Enter</code> to activate buttons. The ARIA design pattern guide provides some guidance here.</p>
<p>Finally, ensure that your keyboard shortcuts are discoverable. A common practice is to have a keyboard shortcut legend (on-screen text) to inform the user that shortcuts exist. For example, "Press ? for keyboard shortcuts.". Alternatively, a hint such as a tooltip can be used to inform a user about the shortcut.</p>
<p>The performance of managing shortcuts can not be overstated. An important example is a navigation drawer. If you add a UI component to a page, you need to direct focus to the element inside it; otherwise, the user may have to tab the entire page to get there. This can be a frustrating experience, so be sure to test focus for all keyboard navigable components on your page.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Tip: You can use the <a target="_self" href="https://github.com/puppeteer/puppeteer">Puppeteer</a> to automate running keyboard accessibility tests for toggling UI states. <a target="_self" href="https://medium.com/walkme-engineering/web-accessibility-testing-d499a7f7a032">WalkMe Engineering</a> has a great guide on this I recommend reading.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742386809604/e263aafc-36c5-46e2-bee8-c3018ffb0fdb.gif" alt class="image--center mx-auto" /></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Example for expanding and collapsing a category with the Space key</span>
<span class="hljs-keyword">const</span> category = <span class="hljs-keyword">await</span> page.$(<span class="hljs-string">`.category`</span>);

<span class="hljs-comment">// verify tabIndex, role and focus</span>
expect(<span class="hljs-keyword">await</span> page.evaluate(<span class="hljs-function"><span class="hljs-params">elem</span> =&gt;</span> elem.getAttribute(<span class="hljs-string">`role`</span>), category)).toEqual(<span class="hljs-string">`button`</span>);
expect(<span class="hljs-keyword">await</span> page.evaluate(<span class="hljs-function"><span class="hljs-params">elem</span> =&gt;</span> elem.getAttribute(<span class="hljs-string">`tabindex`</span>), category)).toEqual(<span class="hljs-string">`0`</span>);
expect(<span class="hljs-keyword">await</span> page.evaluate(<span class="hljs-function"><span class="hljs-params">elem</span> =&gt;</span> <span class="hljs-built_in">window</span>.document.activeElement === elem, category)).toEqual(<span class="hljs-literal">true</span>);

<span class="hljs-comment">// verify aria-expanded = false</span>
expect(<span class="hljs-keyword">await</span> page.evaluate(<span class="hljs-function"><span class="hljs-params">elem</span> =&gt;</span> elem.getAttribute(<span class="hljs-string">`aria-expanded`</span>), category)).toEqual(<span class="hljs-string">`false`</span>);

<span class="hljs-comment">// toggle category by pressing Space</span>
<span class="hljs-keyword">await</span> page.keyboard.press(<span class="hljs-string">'Space'</span>);

<span class="hljs-comment">// verify aria-expanded = true</span>
expect(<span class="hljs-keyword">await</span> page.evaluate(<span class="hljs-function"><span class="hljs-params">elem</span> =&gt;</span> elem.getAttribute(<span class="hljs-string">`aria-expanded`</span>), category)).toEqual(<span class="hljs-string">`true`</span>);
</code></pre>
<h3 id="heading-mind-the-html-semantic">Mind the HTML semantic</h3>
<p>The Browser derives the DOM Tree to create the Accessibility Tree. This is possible because the DOM Tree has some semantic meaning implicit in HTML. This means that by correctly using HTML semantics, we will have a more accessible site.</p>
<p>Let’s see some important things that have into consideration:</p>
<p><strong>Embrace the element’s nature:</strong></p>
<p>You’ve likely seen a pseudo-button or pseudo-link before. These are elements that try to replicate the functionality of a button or anchor, on other elements. A <code>div</code> with an <code>onclick</code>, for example. This is <em>almost</em> never a good idea. The effort required to make these accessible far out-weighs whatever reason you have for implementing them. Let’s take a quick look at the features built into the <code>&lt;button&gt;</code> element.</p>
<ul>
<li><p>Focusable: A button can be focused by tabbing</p>
</li>
<li><p>Keyboard interactions: Pressing enter or space while focused will activate the button</p>
</li>
<li><p>Screen readers announce the element as a button</p>
</li>
<li><p>Additional attributes such as: <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-autofocus">autofocus</a>, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-disabled">disabled</a>, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type">type</a>, and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button">many others</a>.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742645252011/4358476d-3762-4d6f-a7e2-2cb35c7e9eaa.webp" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><em>Why are devs drawn to this anti-pattern? The most common reason I’ve seen is that it’s an easy way to remove all browser styles from the button. Today, there is an easier solution to that problem: Simply add the </em><a target="_blank" class="ag qx" href="https://developer.mozilla.org/en-US/docs/Web/CSS/all"><em>unset</em></a><em> style to your button’s css: </em><code>button { all: unset }</code></div>
</div>

<p>We should not abuse the <code>div</code> element. Instead, we can use elements like <code>nav</code>, <code>footer</code>, <code>article</code>, <code>section</code>, <code>address</code>, <code>aside</code> elements. They will provide some crucial implicit content to the user’s device.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742645029239/36bae366-048e-405f-8a4e-bc79dff7da46.webp" alt class="image--center mx-auto" /></p>
<p><strong>Non-text contents</strong></p>
<p>For those elements that don’t result in text content, it is hard for the browser to reason about.</p>
<p>For input elements, there is a simple semantic solution: use the label element. We have two ways to use it:</p>
<ul>
<li><p><strong>1.</strong> Explicit (recommended): by using the <code>label</code> element with the <code>for</code> attribute</p>
</li>
<li><p><strong>2.</strong> Implicit: by wrapping the <code>input</code> in a label element</p>
</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- Wrapping element in Label --&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> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>&gt;</span>Terms and Conditions
<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Using the 'for' attribute  --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"terms"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"terms"</span>&gt;</span>Terms and Conditions<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
</code></pre>
<p>There are a couple of things to have in mind. The input <code>label</code> should be visible. Otherwise, screen readers won’t voice it. Interactive elements such as links are discouraged from any <code>label</code>. They might lead to accidental clicks or simply fail to be voiced properly.</p>
<pre><code class="lang-xml">
<span class="hljs-comment">&lt;!-- ❌ Avoid --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"terms"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"terms"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"terms"</span>&gt;</span>I accept the <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"..."</span>&gt;</span>Terms and Conditions<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

<span class="hljs-comment">&lt;!-- ✅ Recommended --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"terms"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"terms"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"terms"</span>&gt;</span>I accept the Terms and Conditions.<span class="hljs-tag">&lt;/<span class="hljs-name">label</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">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"..."</span>&gt;</span>Available here<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
</code></pre>
<p><strong>Correct usage of Headings</strong></p>
<p>There are six levels of section headings in HTML <code>&lt;h1&gt;</code> to <code>&lt;h6&gt;</code>. They are relevant to both users and search engines. A proper structure will help better orientate the users and rank you site properly.</p>
<p>This is a list of things to have in mind:</p>
<ul>
<li><p>There should be only one <code>h1</code> in your site at all times. It is meant to be the headline of your page. It should contain a relevant description of the content.</p>
</li>
<li><p>Avoid using those elements to resize text. In that scenario <code>font-size</code> should be used.</p>
</li>
<li><p>Avoid skipping heading levels. Start from <code>h1</code> all the way down to <code>h6</code>.</p>
</li>
</ul>
<p><strong>Give links the proper name</strong></p>
<ul>
<li><p>The link must be recognizable. They should be either underlined or bold when resizing within a block of text (don’t just rely on color to denote it’s a link).</p>
</li>
<li><p>Ensure the link text makes sense on its own or give it a custom label (see below). Avoid “click here“ in the link text. Other ambiguous links, such as “more“ or “continue“ can be confusing.</p>
</li>
<li><p>Any links that open in a new tab or window should give screen reader users advance warning by setting the aria-label attribute on the anchor link(see below).</p>
</li>
<li><p>Links that point to the PDF document should open in a new tab.</p>
</li>
<li><p>Here’s an example of a link that has a custom label and opens in a new window.</p>
</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">”#”</span> <span class="hljs-attr">target</span>=<span class="hljs-string">”_blank”</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">”Download</span> <span class="hljs-attr">the</span> <span class="hljs-attr">2022</span> <span class="hljs-attr">report</span>, <span class="hljs-attr">opens</span> <span class="hljs-attr">in</span> <span class="hljs-attr">a</span> <span class="hljs-attr">new</span> <span class="hljs-attr">tab</span>”&gt;</span>Download<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p><strong>Rules of HTML display</strong></p>
<ul>
<li><p>If a piece of HTML content is set to <code>display:none</code>, this content will also be ignored by assistive technologies.</p>
</li>
<li><p>However, keep in mind that content that is set to <code>opacity:0</code> or <code>visibility: hidden</code> will be reachable by assistive technologies.</p>
</li>
</ul>
<p><strong>Telephone numbers and email addresses should always be hyperlinked</strong></p>
<p>Some screen readers do not enable these as clickable links as default, so this needs to be accounted for.</p>
<h3 id="heading-audio-and-video-101">Audio and Video 101</h3>
<p>Play controls (play, pause, volume, etc.) should always be available for screen readers and keyboards to interact it.</p>
<p>In addition, you should always provide captions for video and live audio and aim to make text transcripts available for all audio content.</p>
<h3 id="heading-include-alt-text-for-images">Include alt text for images</h3>
<p>We have seen earlier how <code>input</code> where challenging for screen screenreaders. The same is true for images. The screen reader needs an alternate way to understand the content of the image.</p>
<p>That is where the <code>alt</code> comes to play. It is a native HTML attribute that provides alternative information for the user when he can’t view the element. That might be because he is a screen reader or because the image failed to load. Even if crawlers can now “see“ the image, having an accurate description will help the SEO.</p>
<p>Some useful guidelines:</p>
<ul>
<li><p>the text should describe the image if it contains information</p>
</li>
<li><p>if the image is a link, it should describe where it is going.</p>
</li>
<li><p><code>alt=""</code> might be used in cosmetic decoration images that are not relevant to the user.</p>
</li>
<li><p>Purely decorative images also need the HTML role attribute set:</p>
<pre><code class="lang-xml">  role="presentation"
</code></pre>
</li>
<li><p>If the image is a headshot of a person and their name is already being displayed underneath or next to the photo, the alt should also be empty in this case. This will prevent assistive technologies from reading out the person’s name twice. For example, this would be the markup for the headshot with the person’s name under it.</p>
<pre><code class="lang-xml">  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">’/images/walter-white.jpg’</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">””</span> <span class="hljs-attr">role</span>=<span class="hljs-string">”presentation”/</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Walter White 👨🏻‍🔬 <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
</code></pre>
</li>
</ul>
<h3 id="heading-use-aria-attributes">Use ARIA attributes</h3>
<p>The Accessible Rich Internet Application is a set of attributes that are designed to boost the accessibility of your page. When using the correct HTML semantics you get those for free. They should therefore only be used when the native HTML semantics require additional input.</p>
<p>Let’s see an obvious example:</p>
<pre><code class="lang-xml">// ❌ bad usage
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"checkbox”&gt;...&lt;/div&gt;
// ✅ recommended, `role=checkbox` is implicit
&lt;input type=”checkbox” name="</span><span class="hljs-attr">terms</span>"&gt;</span>
</code></pre>
<p>Let’s see a more complex example:</p>
<pre><code class="lang-xml">
<span class="hljs-comment">&lt;!-- Manually building progress --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>
  <span class="hljs-attr">id</span>=<span class="hljs-string">"task-completed"</span>
  <span class="hljs-attr">role</span>=<span class="hljs-string">"progressbar"</span>
  <span class="hljs-attr">aria-valuenow</span>=<span class="hljs-string">"55"</span>
  <span class="hljs-attr">aria-valuemin</span>=<span class="hljs-string">"0"</span>
  <span class="hljs-attr">aria-valuemax</span>=<span class="hljs-string">"100"</span>
&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-comment">&lt;!-- ✅ using dedicated element (preferred) --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">progress</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"task-completed"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"55"</span> <span class="hljs-attr">max</span>=<span class="hljs-string">"100"</span>&gt;</span>55 %<span class="hljs-tag">&lt;/<span class="hljs-name">progress</span>&gt;</span>
</code></pre>
<p>Let’s see another example. If we want to present some advisory information we can use the <code>role="status"</code>. The screen reader will properly communicate the message to the user.</p>
<pre><code class="lang-xml">// ✅ Using status for success messages
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"status"</span>&gt;</span>Your changes were saved.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>How can we make sure that we are enforcing ARIA accessibility in your codebase? By using those tags to make queries and assertions in our <code>e2e</code>, <code>component</code>, and <code>integration</code> tests. The whole team would be more ARIA aware and we would have some semantic selectors.</p>
<h3 id="heading-color-contrast">Color Contrast</h3>
<p>When building a site, it is important to maintain a good color contrast between the background and the foreground content. This will ensure that your content stays legible.</p>
<p>There are some ratios established by the WCAG. The success is measured by where your site lands.</p>
<ul>
<li><p>Minimum Contrast (AA)</p>
</li>
<li><p>Enhanced Contrast (AAA)</p>
</li>
<li><p>Non-text Contrast (AA)</p>
</li>
</ul>
<p>There are some tools like WebAim that can help achieve the desired output of success.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742474663917/2a3b72ee-1efa-4f9f-87db-d9bfc73585eb.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-always-test-your-page-by-using-your-keyboard">Always test your page by using your keyboard</h3>
<ul>
<li><p>You should be able to navigate through your page with the Tab key. Typically, the expected flow is left to right, top to bottom.</p>
</li>
<li><p>If the keyboard focus disappears and jumps out of order, this needs to be fixed and usually means something will not work as expected on the screen reader as well.</p>
</li>
<li><p>All clickable elements should fire when pressing Enter.</p>
</li>
<li><p>Links that contain a dropdown menu should open when pressing ENTER or SPACEBAR.</p>
</li>
<li><p>Links within a submenu/drop-down should be reachable via TAB or using the UP and DOWN ARROWS.</p>
</li>
<li><p>Checkboxes and radio buttons should be selectable with the SPACEBAR.</p>
</li>
</ul>
<h3 id="heading-account-for-the-page-zoom">Account for the page zoom</h3>
<ul>
<li><p>You should able to zoom the browser view up to 200% without loss of content and functionality.</p>
</li>
<li><p>WCAG 2.1 requires content to be zoomable up to 400% without the need for vertically scrolling (except when necessary).</p>
</li>
</ul>
<h3 id="heading-include-a-visually-hidden-skip-to-main-content-link-before-the-global-navigation">Include a visually hidden “Skip To Main Content“ link before the global navigation</h3>
<ul>
<li><p>This allows assistive technologies to bypass the global navigation and the site header and jump to the main content.</p>
</li>
<li><p>Typically, the link remains hidden, but it should become visible when it receives keyboard focus.</p>
</li>
<li><p>When clicked, this link should drop the user to an element on the page that holds the main content.</p>
</li>
</ul>
<h3 id="heading-a-word-on-icons">A word on icons</h3>
<ul>
<li><p>Most icons can be set to be ignored by the screen readers since they are purely decorative.</p>
</li>
<li><p>If you are using font icons and it acts as a link, there must be an associated text that describes the link.</p>
</li>
<li><p>Avoid using the &lt;i&gt; tag for displaying icons. Some screen readers will understand this to mean <strong><em>italics</em></strong>.</p>
</li>
</ul>
<h3 id="heading-be-wary-of-hover-only-content">Be wary of hover-only content</h3>
<ul>
<li><p>Any content that can only be viewed by mouse hover will likely be ignored by assistive technologies or get cut off if a user has their screen magnified. The best practice is to use clicks to show or hide vital content.</p>
</li>
<li><p>If that is not possible, make sure the content that is displayed on hover should also be viewable on keyboard focus or when pressing ENTER depending on the behavior of the component.</p>
</li>
</ul>
<h3 id="heading-removing-focus-outline">Removing focus outline</h3>
<p>It’s not uncommon to see an app where the focus outline has been removed. This is problematic as people with mobility problems will often use an app with keyboard interactions, and rely on the outline. While I agree, it doesn’t always look pretty, there are better solutions than removing it.</p>
<p><strong>Better focus styles with box-shadow</strong></p>
<p>If you want more control over the look of the focus outline, you can override the styles to use <code>box-shadow</code>. There is a caveat here though. When a Windows high-contrast theme is turned on the <code>box-shadow</code> wont be visible to the user. We can get the best of both worlds though by setting a <code>box-shadow</code>, and <code>outline-color: transparent</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742645588021/748f7663-0376-45c0-adf7-d469826b28b5.webp" alt class="image--center mx-auto" /></p>
<p><strong>Better UX with</strong> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible"><strong>focus-visible</strong></a></p>
<p>If you’re like me, you really don’t like when you click a button and it shows the focus styles. This can be prevented by using <code>:focus-visible</code>. This allows the focus styles to appear only when the element has been tabbed to.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742645655376/e0818082-38d9-4c57-bdbf-5d119c1f268a.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-pay-close-attention-to-form-controls">Pay close attention to form controls</h3>
<ul>
<li><p>Ensure form controls have descriptive labels and introductions regardless if the label is visible on the page or not.</p>
</li>
<li><p>Relying on the input placeholder’s text to act as the label is bad practice.</p>
</li>
<li><p>Keep form error messages close to the corresponding user input. Always provide text so the screen reader can read the errors.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742645362045/ef840130-008b-47f8-8f4a-0cf7fbdb134d.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-leverage-screen-reader-only-content-when-applicable">Leverage screen reader only content when applicable</h3>
<p>When the standard HTML content is too complex for a screen reader to understand, such as for charts, graphs, infographics, etc., your best option is to create a screen reader only content. This involves:</p>
<ul>
<li><p>Creating a separate version of this content using simple text that typical users will not see on the page but will be available for assistive technologies.</p>
</li>
<li><p>In other words, you will have two versions of the same content: one for the browser and one for the screen reader. The screen version should be placed right before and after the browser content.</p>
</li>
<li><p>Many frontend frameworks such as Bootstrap offer a special CSS class that you can apply to your screen reader only content. <em>(class=”sr-only”)</em></p>
</li>
<li><p>The standard browser content that visually appear on the page needs to be hidden from the screen reader so it doesn't read duplicate information. This can be done by applying the area-hidden attribute to this element and setting this to true <em>(aria-hidden=”true”)</em></p>
</li>
</ul>
<h3 id="heading-rules-for-models-and-all-dialog-boxes">Rules for models and all dialog boxes</h3>
<ul>
<li><p>Keyboard focus should be trapped inside the modal window when it is opened and visible on the screen. Meaning, that only the items inside the modal should be focusable. Other page elements should be inaccessible by a keyboard and screen reader.</p>
</li>
<li><p>The ESC button should always allow the user to close the modal.</p>
</li>
<li><p>There should always be an obvious way for the user to exit the modal via a button.</p>
</li>
<li><p>The wrapping &lt;div&gt; element for the modal should utilize the following attributes:</p>
</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">”-1</span>" <span class="hljs-attr">role</span>=<span class="hljs-string">”dialog”</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">”Contact</span> <span class="hljs-attr">Us</span> <span class="hljs-attr">Dialog</span>”&gt;</span>
</code></pre>
<ul>
<li><p><strong>tabindex</strong>: indicates if an element can receive user focus. It should be set to –1 when the modal is hidden and then switched to 0 with JavaScript when the modal is present on the screen. Many UI frameworks handle this behavior behind the scenes.</p>
</li>
<li><p><strong>role=”dialog”:</strong> tells screen readers and other tools that this element should behave like a dialog.</p>
</li>
<li><p><strong>aria-label:</strong> defines an accessible label for interactive elements to be read out by screen readers. You can also use <em>aria-labelled by</em>: which accepts the id of an HTML element that holds the text you want to use as the label.</p>
</li>
</ul>
<h3 id="heading-rules-for-carousels-and-sliders">Rules for carousels and sliders</h3>
<ul>
<li><p>There should always be next and previous controls.</p>
</li>
<li><p>There should always be a clear way for the user to stop or pause the carousel/slider. This can be done by adding both a stop/pause button and a play button.</p>
</li>
<li><p>When the carousel/slider moves from one slide to the next, a screen reader should read out what slide it is currently on. For example “Slide 2 of 4“.</p>
</li>
<li><p>If the carousel or slider is displaying text on any of the slides, this text needs to be read out by the screen reader as the slider moves from slide to slide. This can only be done with JavaScript and some custom HTML aria-attributes. Follow this <a target="_blank" href="https://www.w3.org/WAI/tutorials/carousels/working-example/">example</a> to see how you can implement this.</p>
</li>
<li><p>As always, ensure your carousel can be operated with a keyboard.</p>
</li>
</ul>
<h3 id="heading-accessibility-tools-and-testing">Accessibility tools and testing</h3>
<p>There are over 100 tools available to evaluate the accessibility of your site and its components. Some tools are automated while others require manual testing.</p>
<p>Here are a few for your consideration:</p>
<ul>
<li><p><a target="_blank" href="http://www.deque.com/products/axe/">Axe</a> provides automated accessibility testing for your framework or browser of choice. <a target="_blank" href="https://www.deque.com/blog/axe-and-attest-integration-puppeteer/">Axe Puppeteer</a> can be used for writing automated accessibility tests.</p>
</li>
<li><p>A <a target="_blank" href="https://developer.chrome.com/docs/lighthouse">Lighthouse</a> Accessibility audit provides helpful insights for discovering common accessibility issues. The accessibility score is a weighted average of all accessibility audits based on A<a target="_blank" href="https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md">xe user impact assessments</a>. For monitoring accessibility with continuous integration, see <a target="_blank" href="https://github.com/GoogleChrome/lighthouse-ci">Lighthouse CI</a>.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742644516061/9f1233cd-a391-4991-a690-11597517c743.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><a target="_blank" href="http://Tenon.io">Tenon.io</a> is useful for testing common accessibility problems. Tenon has strong integration support across build tools, browsers (through extensions), and even text editors.</p>
</li>
<li><p>There are many library- and framework-specific tools for highlighting accessibility issues with components. For example, use <a target="_blank" href="https://www.npmjs.com/package/eslint-plugin-jsx-a11y">eslint-plugin-jsx-a11y</a> to highlight accessibility issues for React components in your editor.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742644547630/677dd8ee-a68e-4a66-ac41-3c53d170c01c.png" alt class="image--center mx-auto" /></p>
<p>  If you use Angular, <a target="_blank" href="https://web.dev/articles/accessible-angular-with-codelyzer">codelyzer</a> provides in-editor accessibility audits too:</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742644646906/739b3d9e-def3-42c1-b7b0-250b39352af0.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<h3 id="heading-work-with-assistive-technologies">Work with assistive technologies</h3>
<ul>
<li><p>You can examine the way that assistive technologies see web content by using <a target="_blank" href="https://developer.apple.com/documentation/accessibility/accessibility-inspector">Accessibility Inspector</a> (Mac) or <a target="_blank" href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd373661\(v=vs.85\).aspx">Windows Automation API Testing Tools</a> and <a target="_blank" href="http://accessibility.linuxfoundation.org/a11yweb/util/accprobe/">AccProbe</a> (Windows). You can also see the full accessibility tree that Chrome creates by navigating to <code>about://accessibility</code>.</p>
</li>
<li><p>The best way to test for screen reader support on a Mac is by using the VoiceOver utility. Use <code>⌘F5</code> to enable or disable it, <code>Ctrl+Option ←→</code> to move through the page, and <code>Ctrl+Shift+Option + ↑↓</code> to move up and down the accessibility tree. For more detailed instructions, see the <a target="_blank" href="http://www.apple.com/voiceover/info/guide/_1131.html">full list of VoiceOver commands</a> and the <a target="_blank" href="http://www.apple.com/voiceover/info/guide/_1131.html#vo27972">list of VoiceOver Web commands</a>.</p>
</li>
<li><p>On Windows, <a target="_blank" href="http://www.nvaccess.org/">NVDA</a> is a free, open-source screen reader. However, it has a steep learning curve for sighted users.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742644848866/56f63d1c-c5e7-4894-b6ae-250c6369ce36.jpeg" alt class="image--center mx-auto" /></p>
</li>
<li><p>ChromeOS has a <a target="_blank" href="https://support.google.com/chromebook/answer/7031755">built-in screenreader</a>.</p>
</li>
</ul>
<p>We have a long way to go to improve accessibility on the web. Per the <a target="_blank" href="https://almanac.httparchive.org/en/2019/accessibility">Web Almanac</a>:</p>
<ul>
<li><p>4 out of every 5 sites have text that blends into the background, making them unreadable.</p>
</li>
<li><p>49.91% of pages still fail to provide <code>alt</code> attributes for some of their images.</p>
</li>
<li><p>Only 24% of pages that use buttons or links include labels.</p>
</li>
<li><p>Only 22.33% of pages provide labels for all their form inputs.</p>
</li>
</ul>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://ahrefs.com/seo-audit-tool">http</a><a target="_blank" href="https://blog.openreplay.com/seo-basics-for-web-developers/?ref=dailydev">s://blog.openreplay.com/seo-basics-for-web-</a><a target="_blank" href="https://www.npmjs.com/package/eslint-plugin-jsx-a11y">developers/?ref=dailyd</a><a target="_blank" href="https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md">ev</a></p>
<p><a target="_blank" href="https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md">https://dev.to</a><a target="_blank" href="https://dev.to/acidop/12-easy-seo-tips-every-developer-should-know-52k3?context=digest">/acidop/12-easy-seo-tips-every-developer-should-</a><a target="_blank" href="https://www.w3.org/WAI/tutorials/carousels/working-example/">kn</a><a target="_blank" href="https://github.com/GoogleChrome/lighthouse-ci">ow-52k3?conte</a><a target="_blank" href="https://dev.to/acidop/12-easy-seo-tips-every-developer-should-know-52k3?context=digest">xt=digest</a></p>
<p><a target="_blank" href="https://dev.to/thesohailjafri/the-must-have-seo-checklist-for-developers-192i?ref=dailydev">https://dev.to/thesohail</a><a target="_blank" href="http://www.apple.com/voiceover/info/guide/_1131.html">jafri/the-must-have-seo-checkli</a><a target="_blank" href="https://dev.to/thesohailjafri/the-must-have-seo-checklist-for-developers-192i?ref=dailydev">st-for-d</a><a target="_blank" href="http://www.apple.com/voiceover/info/guide/_1131.html#vo27972">evelopers-192i?ref=dailydev</a></p>
<p><a target="_blank" href="http://www.apple.com/voiceover/info/guide/_1131.html#vo27972">h</a><a target="_blank" href="https://www.freecodecamp.org/news/tips-to-boost-your-seo/">ttps://www.freecodecamp.org/news/tips-to-boost-your-seo/</a></p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/how-to-make-a-website-seo-friendly/">https://www.freecodecamp.org/news/how-to-make-a-website-seo-friendly/</a></p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/nextjs-seo/">https://www.freecodecamp.org/news/nextjs-seo/</a></p>
<p><a target="_blank" href="https://medium.com/@sassenthusiast/next-js-seo-best-practices-for-higher-rankings-f315c5c2db32">https://medium.com/@sassenthusiast/next-js-seo-best-practices-for-higher-rankings-f315c5c2db32</a></p>
<p><a target="_blank" href="https://blog.stackademic.com/boosting-seo-in-next-js-essential-steps-for-effective-meta-tag-integration-b42690f1bc02">https://blog.stackademic.com/boosting-seo-in-next-js-essential-steps-for-effective-meta-tag-integration-b42690f1bc02</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/5-web-accessibility-tips-e2ba0d3726e5">https://medium.com/better-programming/5-web-accessibility-tips-e2ba0d3726e5</a></p>
<p><a target="_blank" href="https://web.dev/articles/a11y-tips-for-web-dev#improve_keyboard_focus">https://web.dev/articles/a11y-tips-for-web-dev#improve_keyboard_focus</a></p>
<p><a target="_blank" href="https://uxplanet.org/30-must-know-best-practices-for-web-accessibility-df1b3258ebdc">https://uxplanet.org/30-must-know-best-practices-for-web-accessibility-df1b3258ebdc</a></p>
<p><a target="_blank" href="https://medium.com/fbdevclagos/why-web-accessibility-is-important-and-how-you-can-accomplish-it-4f59fda7859c">https://medium.com/fbdevclagos/why-web-accessibility-is-important-and-how-you-can-accomplish-it-4f59fda7859c</a></p>
<p><a target="_blank" href="https://blog.stackademic.com/should-a-url-end-with-a-trailing-slash-whats-the-difference-a8eacc430b47">https://blog.stackademic.com/should-a-url-end-with-a-trailing-slash-whats-the-difference-a8eacc430b47</a></p>
]]></content:encoded></item><item><title><![CDATA[API Integration Patterns]]></title><description><![CDATA[API stands for Application Programming Interface. The “I“ in the API is the key part that explains its purpose.
The interface is what the software presents to other humans or programs, allowing them to interact with it.
A good analogy for an interfac...]]></description><link>https://blog.tuanhadev.tech/api-integration-patterns</link><guid isPermaLink="true">https://blog.tuanhadev.tech/api-integration-patterns</guid><category><![CDATA[APIs]]></category><category><![CDATA[REST API]]></category><category><![CDATA[GraphQL]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webhooks]]></category><category><![CDATA[RPC]]></category><category><![CDATA[SOAP API]]></category><category><![CDATA[polling]]></category><category><![CDATA[SocketIO]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Sun, 02 Mar 2025 10:23:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Ype9sdOPdYc/upload/08297685ba66551bc4caa5c7211b4948.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>API stands for Application Programming Interface. The “I“ in the API is the key part that explains its purpose.</p>
<p>The interface is what the software presents to other humans or programs, allowing them to interact with it.</p>
<p>A good analogy for an interface is a remote control. Imagine you have a universal remote that controls your TV, lights, and fans.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740648127034/1338b99b-131b-4ecd-ba43-cf2d9a680be0.png" alt class="image--center mx-auto" /></p>
<p>Let’s break down what a universal remote control can do:</p>
<ul>
<li><p>The remote control has various buttons, each serving a different purpose. One button might change the channel, while another can dim the light of the chandelier, and another can turn on the fan.</p>
</li>
<li><p>When you press a button, it sends a specific signal via infrared, Bluetooth, or wifi to the object you are controlling, instructing it to perform a particular action.</p>
</li>
<li><p>The key feature of the remote is that it allows you to interact with the TV, chandelier, and fan without understanding their internal workings. All that complexity is abstracted away. You simply press a button, and you get a response that you can observe immediately.</p>
</li>
</ul>
<p>APIs work in the similar way.</p>
<ul>
<li><p>APIs can have various endpoints, each designed to perform a specific action. For example, one endpoint might retrieve data while another updates or deletes it.</p>
</li>
<li><p>When you send a request to an endpoint, it communicates with the server using HTTP methods—GET, POST, PUT, and DELETE—to instruct it to perform a particular action(such as retrieving, sending, updating, or deleting data).</p>
</li>
<li><p>The key thing about APIs, as with remote controls, is that APIs abstract away the inner workings of the server or the database behind the API. The API allows users, developers, and applications to interact with a software application or perform without needing to understand its internal code or database structure. You simply send a request, and the server processes it and provides a response.</p>
</li>
</ul>
<p>The analogy holds true as long as APIs are more complex than a remote control. However, the basic principle of operation of an API and a universal remote is quite similar.</p>
<p>This article will explain API integration patterns, which can be divided into two categories: Request-Response (SOAP, REST, RPC, and GraphQL) and event-driven APIs (Pooling, WebSockets, and WebHooks).</p>
<p><img src="https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4e965c2-b545-4f79-a489-e0e72d473c06_1109x1600.png" alt /></p>
<h1 id="heading-request-response-integration">Request-Response Integration</h1>
<p>In a request-response integration, the client initiates the action by sending a request to the server and then waits for the response.</p>
<p>Different patterns of request-response integration exist, but at a high level, they all conform to the same rule of the client initiating a request and waiting for a response from the server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740655731552/8e4b1852-a7b7-47cc-b486-161de24421c1.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-rpc">RPC</h2>
<p>RPC stands for Remote Procedure Call. Unlike REST APIs, which are all about resources, RPC is all about actions. With RPC, the client executes a block of code on the client.</p>
<p>Think of a restaurant without a menu. There is no dish you can request in this restaurant. Instead, you request a specific action to be performed by the restaurant.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740655109901/35c2ff35-6ee5-46e9-aadf-88bc3c635258.png" alt class="image--center mx-auto" /></p>
<p>With a REST API, the guest would have simply asked for some fish and chips. With RPC, they have to give instructions on what they want the kitchen to prepare.</p>
<p>In the RPC pattern, the client calls a specific procedure on the server and waits for the result. The procedure to prepare and what gets prepared are tightly bound together. This might give the client very specific and tailored results, but it lacks the flexibility and ease of use of REST.</p>
<p>Most restaurants use menus instead of following their customers' custom requests. This partly explains why RPC is a less popular integration pattern than REST.</p>
<h2 id="heading-soap">SOAP</h2>
<p><strong>Simple Object Access Protocol (SOAP)</strong> is a messaging protocol used for exchanging structured data between different systems over the Internet. SOAP is an XML-based protocol and is considered one of the earliest web service protocols. SOAP was first introduced in 1998 by Microsoft as a successor to Common Object Request Broker Architecture (CORBA) and Distributed Component Object Model (DCOM). SOAP was designed to provide a platform-independent way to exchange data between different systems over the Internet. SOAP was later standardized by the World Wide Web Consortium (W3C) in 2003.</p>
<p>SOAP APIs were widely used in the early days of web services and are still used in several industries and sectors today, although REST and GraphQL have become more popular in recent years. SOAP might be the most beneficial option for developing an API when sensitive data needs to be transmitted, complex data structures need to be supported, or a reliable and standardized protocol is needed.</p>
<p>SOAP APIs use XML as the main format for data transmission. XML stands for Extensible Markup Language. It’s a markup language that allows users to create custom tags and attributes to describe the structure and content of data. XML uses a set of rules for encoding documents in a format that is both human-readable and machine-readable. This is achieved by using tags to define elements of a document, similar to HTML.</p>
<p>For example, an XML document may have a tag called <code>&lt;person&gt;</code> to define an element representing a person, with nested tags for properties such as <code>&lt;name&gt;</code>, <code>&lt;age&gt;</code>, and <code>&lt;address&gt;</code>. XML also allows users to define custom tags to describe their data in a way that is specific to their needs. XML is widely used in various industries, including finance, healthcare, and government. It is often used for data exchange between different applications and systems, as it provides a standardized way of representing data that can be easily parsed by computers. XML is also used to store configuration files and metadata for various applications.</p>
<p>Overall, XML provides a flexible and extensible way of describing and exchanging data that computers can easily process. However, its use has declined in recent years due to the rise of more modern formats such as JSON and YAML, which are lighter and easier to use for many applications.</p>
<p>Here is an example of how you can make a simple request to a SOAP API from a JavaScript front-end application:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// specify the URL of the SOAP API endpoint</span>
<span class="hljs-keyword">const</span> url = <span class="hljs-string">'http://www.example.com/soap-api'</span>;

<span class="hljs-comment">// specify the SOAP message to send</span>
<span class="hljs-keyword">const</span> soapMessage = <span class="hljs-string">'&lt;?xml version="1.0" encoding="UTF-8"?&gt;'</span> +
                    <span class="hljs-string">'&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://example.com"&gt;'</span> +
                    <span class="hljs-string">'&lt;SOAP-ENV:Header/&gt;'</span> +
                    <span class="hljs-string">'&lt;SOAP-ENV:Body&gt;'</span> +
                    <span class="hljs-string">'&lt;ns1:GetData&gt;'</span> +
                    <span class="hljs-string">'&lt;ns1:Id&gt;123&lt;/ns1:Id&gt;'</span> +
                    <span class="hljs-string">'&lt;/ns1:GetData&gt;'</span> +
                    <span class="hljs-string">'&lt;/SOAP-ENV:Body&gt;'</span> +
                    <span class="hljs-string">'&lt;/SOAP-ENV:Envelope&gt;'</span>;

<span class="hljs-comment">// set the content type of the SOAP message</span>
<span class="hljs-keyword">const</span> contentType = <span class="hljs-string">'text/xml'</span>;

<span class="hljs-comment">// make the fetch request</span>
fetch(url, {
  method: <span class="hljs-string">'POST'</span>, <span class="hljs-comment">// SOAP uses the HTTP POST method to send requests to a server.</span>
  headers: {
    <span class="hljs-string">'Content-Type'</span>: contentType,
    <span class="hljs-string">'SOAPAction'</span>: <span class="hljs-string">'http://example.com/GetData'</span>
  },
  body: soapMessage
})
  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.text())
  .then(<span class="hljs-function"><span class="hljs-params">xml</span> =&gt;</span> {
    <span class="hljs-comment">// handle the XML response</span>
    <span class="hljs-keyword">const</span> parser = <span class="hljs-keyword">new</span> DOMParser();
    <span class="hljs-keyword">const</span> xmlDoc = parser.parseFromString(xml, <span class="hljs-string">'text/xml'</span>);
    <span class="hljs-keyword">const</span> value = xmlDoc.getElementsByTagName(<span class="hljs-string">'Value'</span>)[<span class="hljs-number">0</span>].childNodes[<span class="hljs-number">0</span>].nodeValue;
    <span class="hljs-built_in">console</span>.log(value);
  })
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
</code></pre>
<p>A typical response might look like this:</p>
<pre><code class="lang-typescript">&lt;?xml version=<span class="hljs-string">"1.0"</span> encoding=<span class="hljs-string">"UTF-8"</span>?&gt;
&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV=<span class="hljs-string">"http://schemas.xmlsoap.org/soap/envelope/"</span>&gt;
   &lt;SOAP-ENV:Body&gt;
      &lt;ns1:GetDataResponse xmlns:ns1=<span class="hljs-string">"http://example.com"</span>&gt;
         &lt;ns1:Result&gt;
            &lt;ns1:Id&gt;<span class="hljs-number">123</span>&lt;/ns1:Id&gt;
            &lt;ns1:Value&gt;<span class="hljs-number">42</span>&lt;/ns1:Value&gt;
         &lt;/ns1:Result&gt;
      &lt;/ns1:GetDataResponse&gt;
   &lt;/SOAP-ENV:Body&gt;
&lt;/SOAP-ENV:Envelope&gt;
</code></pre>
<p>The following code extracts the value of the Value element from the XML document object:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> parser = <span class="hljs-keyword">new</span> DOMParser();
<span class="hljs-keyword">const</span> xmlDoc = parser.parseFromString(xml, <span class="hljs-string">'text/xml'</span>);
<span class="hljs-keyword">const</span> value = xmlDoc.getElementsByTagName(<span class="hljs-string">'Value'</span>)[<span class="hljs-number">0</span>].childNodes[<span class="hljs-number">0</span>].nodeValue;
<span class="hljs-built_in">console</span>.log(value); <span class="hljs-comment">// output: 42</span>
</code></pre>
<p>Overall, SOAP responses tend to be more verbose and complex than responses from RESTs and GraphQL APIs due to their use of XML and the envelope format. However, this format provides a standardized way of exchanging information that can be useful in certain industries or use cases.</p>
<h2 id="heading-rest">REST</h2>
<p>REST (Representational State Transfer) is not a framework or library but an architectural style for building web services or APIs. In REST, <strong>everything is a resource identified by a unique URL</strong>, and these resources are manipulated using HTTP methods such as GET (to retrieve the resource), POST (to create a new resource), PUT or PATCH (to update a resource), and DELETE (to remove a resource).</p>
<p>To understand REST APIs, consider the following analogy. Imagine you go to a restaurant and order some food. The menu is extensive, and items are categorically organised. Each item on the menu can be equated to a resource.</p>
<p>First, you call a waiter to get attention, then you place an order. Each request receives a response before you can proceed with another request, like ordering a dish.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740741415310/eb63e0c0-8ede-4271-b608-bd7994345128.png" alt class="image--center mx-auto" /></p>
<p>In REST API terms, the client initiates requests to the server by specifying exactly what it wants using HTTP methods such as GET, POST, PUT, and DELETE on specific URLs (the menu items). Each interaction is stateless, meaning that each request from the client to the server must contain all the information needed to understand and process the request. <strong>The server does not store client contexts between requests,</strong> simplifying design and improving scalability. The client and server’s HTTP request and response bodies carry JSON and XML representations of a resource’s status.</p>
<p><strong>Benefits of REST APIs:</strong></p>
<ul>
<li><p><strong>Simplicity</strong>: Using standard HTTP methods and common data formats makes REST APIs easy to understand and implement.</p>
</li>
<li><p><strong>Interoperability</strong>: REST APIs promote interoperability, as different applications can interact seamlessly regardless of the programming language or platforms used.</p>
</li>
<li><p><strong>Scalability</strong>: The stateless nature of REST APIs allows for easy scaling to handle large columns and requests.</p>
</li>
<li><p><strong>Flexibility</strong>: REST APIs can be updated to various use cases due to their versatile design principles.</p>
</li>
</ul>
<p><strong>Drawbacks of REST APIs</strong></p>
<ul>
<li><p><strong>Statelessness</strong>: REST relies on stateless transactions, meaning each request must complete all the information independently. This can be cumbersome for workflows that require maintaining state across multiple requests, like shopping carts on e-commerce sites.</p>
</li>
<li><p><strong>Limited payload size</strong>: Data Transfer in REST often happens through JSON or XML payloads, which can become quite large if you are dealing with complex data or many queries. This can lead to performance issues.</p>
</li>
<li><p><strong>Lack of discoverability</strong>: REST APIs don’t inherently make it easy for users to understand the functionality or how to interact with them, which can add complexity for new users.</p>
</li>
<li><p><strong>Performance for complex queries</strong>: REST might not be ideal for retrieving specific data points from a large source. Other options, like GraphQL, can be more efficient in such cases.</p>
</li>
</ul>
<p>REST defines <strong>six architectural constraints</strong> an API should follow to be considered genuinely RESTful:</p>
<ol>
<li><p><strong>Client-Server</strong>: This separation of concerns separates the client (the application using the API) from the server (the application providing the API). The client initiates requests, and the server processes them and sends the response.</p>
</li>
<li><p><strong>Stateless</strong>: Each request from the client to the server must contain all the information necessary to understand the request. The server doesn’t store any context about the client between requests. This simplifies communication and improves scalability.</p>
</li>
<li><p><strong>Uniform interface</strong>: This constraint defines a set of rules for how clients interact with the server. These rules include:</p>
<ul>
<li><p><strong>Resource-based</strong>: APIs expose resources that clients can interact with. URLs identify resources.</p>
</li>
<li><p><strong>Standard Methods</strong>: Clients use standard HTTP methods (GET, POST, PUT, DELETE) to perform operations on resources.</p>
</li>
<li><p><strong>Representation</strong>: Data is exchanged between client and server in a standard format like JSON or XML.</p>
</li>
</ul>
</li>
<li><p><strong>Cacheable</strong>: The client may mark the server responses as cacheable. This allows clients to store frequently accessed data locally, reducing server loads and improving performance.</p>
</li>
<li><p><strong>Layered System</strong>: The architecture may consist of multiple layers (proxies, caches, load balancers) between the client and server. These layers can improve performance, security, and scalability.</p>
</li>
<li><p><strong>Code on Demand (Optional)</strong>: While not strictly mandatory, a RESTful API may optionally transfer executable code to the client. Clients can use this code to extend its functionality or process data locally.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740745619410/f71b1b79-69d6-4c28-8038-61e52b3ab5b6.webp" alt class="image--center mx-auto" /></p>
<p>An example of a REST API call for the API on the <a target="_blank" href="https://api.example.com/">https://api.example.com</a> address when you want to get the information about the user ID 500 is the following, using the curl command-line tool curl <code>-X GET</code> <a target="_blank" href="https://api.example.com/users/500"><code>https://api.example.com/users/500</code></a> <code>-H "Accept: application/json</code> . The last part (Accept: application/json) is a header that indicates that the client expects to receive the data in JSON format. A response would be a result in the JSON format, and 200 would be the response status code.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740745876832/2085bf04-50a7-4275-8035-809bc2e43dab.webp" alt class="image--center mx-auto" /></p>
<p>Even though REST is not the best choice when performances are essential, we can do a few things here, such as <strong>caching</strong>, <strong>pagination</strong>, <strong>payload compression</strong>, and more.</p>
<h2 id="heading-graphql">GraphQL</h2>
<p><a target="_blank" href="https://graphql.org/">GraphQL</a> is a query language for APIs released and open-sourced in 2015 by Meta. The <a target="_blank" href="https://graphql.org/foundation/">GraphQL Foundation</a> now oversees it. GraphQL is a server-side runtime environment that enables clients to request the data they need from an API. Unlike traditional REST APIs, which often require multiple requests to get different pieces of data, GraphQL allows you to specify all the data you need in a single request. The GraphQL specification was open-sourced in 2015.</p>
<p>Think of a restaurant that allows you to customize your own dish by specifying exact quantities or ingredients you want.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740817268204/67998909-4bab-4117-91cf-85a5e7dbac94.png" alt class="image--center mx-auto" /></p>
<p>This may look similar to the RPC pattern, but notice that the customer is not saying how the food should be made; they are just customizing their order by removing some ingredients (no salt) and reducing the number of some items (two pieces of fish instead of four)</p>
<p>Because GraphQL doesn't over- or under-fetch results when queries are sent to your API, it guarantees that the app built with GraphQL is <strong>scalable, fast, and stable.</strong> It also allows for combining multiple operations into a single HTTP request.</p>
<p>GraphQL APIs are organized in <strong>terms of type and field, not endpoints</strong>. Using the <strong>GraphQL Schema Definition Language (SDL)</strong>, you define your data as a schema. This schema serves as a contract between the client and the server, detailing precisely what queries can be made, what types of data can be fetched, and what the response will look like.</p>
<p><strong>Benefits of GraphQL:</strong></p>
<ul>
<li><p><strong>Efficient data fetching</strong>: You only request the exact data you need, eliminating the issue of over-fetching and under-fetching that can happen with REST. This can significantly improve performance, especially for complex data models.</p>
</li>
<li><p><strong>Flexible and Declarative</strong>: GraphQL uses a schema that defines the available data and how to access it. This schema allows developers to write clear and concise queries that specify their exact data needs.</p>
</li>
<li><p><strong>Single request for multiple resources</strong>: Unlike REST, which requires multiple API calls to fetch data from different endpoints, GraphQL allows combining queries into a single request for improved efficiency.</p>
</li>
<li><p><strong>Versioning and Backward Compatibility</strong>: GraphQL schema changes can be improved with versioning, ensuring existing clients aren’t affected while allowing for future growth.</p>
</li>
</ul>
<p><strong>Drawbacks of GraphQL:</strong></p>
<ul>
<li><p><strong>Complexity in query structure</strong>: While flexibility is a strength, writing complex GraphQL queries can be challenging and requires careful planning for readability and maintainability.</p>
</li>
<li><p><strong>Caching</strong>: Caching data with GraphQL is generally more complex than REST APIs, which leverage built-in HTTP cache mechanisms.</p>
</li>
<li><p><strong>Security</strong>: GraphQL exposes your entire data schema, so proper security measures are crucial to prevent unauthorized access to sensitive data.</p>
</li>
<li><p><strong>Learning Curve</strong>: For developers unfamiliar with GraphQL, understanding schema and query syntax involves a learning curve.</p>
</li>
<li><p><strong>Error Handling</strong>: If the library doesn’t parse errors with a status of 200 in the response body, the client must use more intricate logic to handle them.</p>
</li>
</ul>
<p><strong>How it works:</strong></p>
<ul>
<li><p>The client <strong>defines a query in GraphQL syntax</strong>, specifying exactly how the data should be structured and what fields are needed.</p>
</li>
<li><p>The GraphQL server uses a predefined schema to determine the available data and its relationship to other data. This schema defines types, fields, and the relationships between types.</p>
</li>
<li><p>The server executes the query against the schema. For each field in the query, the <strong>server has a corresponding resolver function</strong> that fetches the data for that field.</p>
</li>
<li><p>The server returns a JSON object where the shape directly mirrors the query, populated with the requested data.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740821282031/9e6f1f37-08f2-41a2-89d4-da606515449c.webp" alt class="image--center mx-auto" /></p>
<p>GraphQL supports three core operations that define how the client interacts with the server:</p>
<ul>
<li><p><strong>Queries</strong>: Used to retrieve data from the server. This is the most common operation used in GraphQL.</p>
</li>
<li><p><strong>Mutations</strong> modify data on the server. This could involve creating new data, updating existing data, or deleting data.</p>
</li>
<li><p><strong>Subscriptions</strong> are used to establish real-time communication between the client and the server. The server can then update the client whenever the requested data changes.</p>
</li>
</ul>
<p>An example of a GraphQL request consists of an operation and the data you are requesting and manipulating.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740822688168/69f6f022-af07-449a-a248-574ed705ac46.webp" alt class="image--center mx-auto" /></p>
<p>This query retrieves data for a user with ID 1. It also fetches nested data for the user’s posts, including their IDs and titles.</p>
<p>The response is a JSON object containing actual data requested by the query or mutation or optional errors.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740823078956/5a148071-0a44-44df-9527-84a7ce968ed9.webp" alt class="image--center mx-auto" /></p>
<p>So, when to choose each of those protocols:</p>
<ul>
<li><p>✅ Use <strong>REST</strong> when you are building a CRUD-style web application or when you work with well-structured data. It’s a go-to for public APIs and services that need to be consumed by a broad range of clients.</p>
</li>
<li><p>✅ Use <strong>gRPC</strong> if your API is private about actions or if performance is essential. Low latency is critical for server-to-server communication. Its use of HTTP/2 and ProtoBuf optimizes efficiency and speed.</p>
</li>
<li><p>✅ Use <strong>GraphQL</strong> if you have a public API that needs to be flexible in customizing requests and you want to add data from different sources into a public API. Use it in client-server communication, while we must get all the data on a single round trip.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740825855252/9d8d9cd0-0024-4ed7-a131-863330160c7c.webp" alt class="image--center mx-auto" /></p>
<h1 id="heading-event-driven-integration">Event-Driven Integration</h1>
<p>This integration pattern is ideal for services with fast-changing data.</p>
<p>Some of these integration patterns are also <a target="_blank" href="https://lightcloud.substack.com/p/synchronous-and-asynchronous-communication">asynchronous</a> and initiated by the server, unlike the request-response patterns, which are <a target="_blank" href="https://lightcloud.substack.com/p/synchronous-and-asynchronous-communication">synchronous</a> and initiated by the client.</p>
<h2 id="heading-polling">Polling</h2>
<p>Let’s use the restaurant analogy again. When you order food, it takes some time for it to be prepared.</p>
<p>Asking the waiter if your order is ready can update you on its status. The more frequently you ask, the closer you will be to having real-time information about your order.</p>
<p>However, this puts unnecessary strain on the waiters, who have to constantly check the status of your order and update you whenever you ask.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740826299781/38463ce7-48de-454b-8cd6-29f49eebcdc6.png" alt class="image--center mx-auto" /></p>
<p>Polling is when the client continuously asks the server if there is new data available with a set frequency. It’s not efficient because many requests may return no new data, thus unnecessarily consuming resources.</p>
<p>The more frequently you poll (make requests), the closer the client gets to real-time communication with the server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740826642768/16397fbc-fb7a-478d-8a46-1ed32b007664.png" alt class="image--center mx-auto" /></p>
<p>Most of the requests during the polling are wasted since they only return something useful to the client once there is a change on the server.</p>
<p>There is, however, another version of polling called long polling. With long polling, the waiter doesn’t respond to the guest straightaway about the status of the order. Instead, the waiter only responds if there is an update.</p>
<p>Naturally, this only works if the guest and the waiter agree beforehand that a slow response from the waiter doesn’t mean that the waiter is being rude and the guest is being ignored.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740827050192/44534aca-359b-45cb-af68-b724e41ca25d.png" alt class="image--center mx-auto" /></p>
<p>With long polling, the server does not respond to the client immediately. It waits until something has changed before responding.</p>
<p>As long as the server and the client agree that the server will hold on to the client’s requests and the connection between the client and the server remains open, this pattern works and can be more efficient than simply polling.</p>
<p>These two assumptions for long polling may be unrealistic, though - the server can lose the client’s requests and/or the connection can be broken.</p>
<p>To address these limitations, long polling adds extra complexity to the process by requiring a directory of the server that contains the connection to the client, which is used to send data to the client whenever the server is ready.</p>
<p>Standard polling, on the other hand, can remain <a target="_blank" href="https://lightcloud.substack.com/i/104443280/stateless-architecture">stateless</a>, making it more <a target="_blank" href="https://lightcloud.substack.com/i/59017006/fault-tolerance">fault-tolerant</a> and scalable.</p>
<h2 id="heading-websockets">WebSockets</h2>
<p>WebSockets provide a persistent, two-way communication channel between the client and server. Once a WebSocket connection is established, both parties can communicate freely, which enables real-time data flows and is more resource-efficient than polling.</p>
<p>Using the restaurant analogy again, a guest orders a meal and then establishes a dedicated communication channel with the waiter so they can freely communicate back and forth about updates and changes to the order until the meal is ready. This means the waiter can also initiate the communication with the guest, which is not the case for the other integration patterns mentioned so far.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740908734465/fff4d861-57ce-4ee3-b576-672eb5e0dc2b.png" alt class="image--center mx-auto" /></p>
<p>WebSockets are similar to long polling. They both avoid the wasteful requests of polling, but WebSockets have the added benefit of having a persistent connection between the client and the server.</p>
<p>WebSockets are ideal for fast, live streaming data, like real-time chat applications. The downside of WebSockets is that the persistent connection consumes bandwidth, so it might not be ideal for mobile applications or in areas with poor connectivity.</p>
<h2 id="heading-webhooks">WebHooks</h2>
<p>WebHooks allow the server to notify the client when new data is available. The client registers a callback URL to the server, and the server sends a message to that URL when there is data to send.</p>
<p>With WebHooks, the client sends requests as usual but can also listen and receive requests like a server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740909546558/465b3132-538d-4713-bb97-229db19f810b.png" alt class="image--center mx-auto" /></p>
<p>Using the restaurant analogy, when the guest orders the meal, they give the waiter a bell (analogous to the callback URL). The waiter goes to the kitchen and rings the bell as soon as the meal is ready. That allows the client to know, in real time, about the progress of his order.</p>
<p>WebHooks are superior to polling because you get real-time updates from the server once something changes, without having to make frequent, wasteful requests to the server about that change.</p>
<p>They are also superior to long polling because long polling can consume more client and server resources as it involves keeping connections open, potentially resulting in many open connections.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>APIs are crucial tools in software development, allowing users and applications to interact with software without understanding its inner workings.</p>
<p>They come in different integration patterns, such as REST, RPC, GraphQL, Polling, WebSockets, and WebHooks.</p>
<p>If you need a simple request-response integration, then REST, RPC, or GraphQL could be ideal. For real-time or near-real-time applications, polling, WebSockets, or WebHooks are ideal.</p>
<p>As with any design problem, the right choice depends on the business case and what tradeoffs you are willing to tolerate.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://www.freecodecamp.org/news/api-integration-patterns/">https://www.freecodecamp.org/news/api-integration-patterns/</a></p>
<p><a target="_blank" href="https://medium.com/@techworldwithmilan/when-to-use-graphql-grpc-and-rest-9d541c0bcfe0">https://medium.com/@techworldwithmilan/when-to-use-graphql-grpc-and-rest-9d541c0bcfe0</a></p>
<p><a target="_blank" href="https://blog.bytebytego.com/p/a-crash-course-in-graphql?utm_source=substack&amp;utm_medium=email">https://blog.bytebytego.com/p/a-crash-course-in-graphql?utm_source=substack&amp;utm_medium=email</a></p>
]]></content:encoded></item><item><title><![CDATA[🔥 My Web Styling Handbook]]></title><description><![CDATA[Are you ready to advance your CSS skills? Whether you are a seasoned pro or just starting out, you have all experienced those moments when your style sheets seem to have a mind of their own. This article will introduce you to some advanced CSS concep...]]></description><link>https://blog.tuanhadev.tech/mastering-css</link><guid isPermaLink="true">https://blog.tuanhadev.tech/mastering-css</guid><category><![CDATA[CSS]]></category><category><![CDATA[CSS3]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[css tips]]></category><category><![CDATA[css-tricks]]></category><category><![CDATA[Advanced CSS]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Sat, 22 Feb 2025 10:04:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/6JVlSdgMacE/upload/383505bad4ac773b7326e485776193eb.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Are you ready to advance your CSS skills? Whether you are a seasoned pro or just starting out, you have all experienced those moments when your style sheets seem to have a mind of their own. This article will introduce you to some advanced CSS concepts, tips, and hacks that are sure to make your life easier and your designs impressive.</p>
<p>In this blog post, we are going to explore some awesome CSS hacks that will help you solve common challenges, improve your workflow, and add some extra pizzazz to your projects. These aren’t just any old tricks - they are practical, powerful, and perfect for UI developers like us who want to create stunning web experiences.</p>
<p>So, grab your favorite beverage, get comfy, and let’s dive into the world of CSS hacks!</p>
<h1 id="heading-css">CSS</h1>
<h2 id="heading-css-fundamental-principles">CSS Fundamental Principles</h2>
<p>CSS has a pretty simple syntax, but there are a lot of fundamental principles in how it works that catch people off guard. This can lead to confusion and a lot of frustration. There are also times when there are multiple ways to do the same thing, and that can lead to extra frustration as well because you don’t know which one is better in any given situation.</p>
<p>CSS really is one of those things that when you first start off with it, it just seems like it’s going to be the easiest thing in the world, and quickly can lead to times where you just want to throw your computer out the window. So with that in mind, let’s look at eight extremely important CSS concepts that, when you understand them, can really help simplify things and make your life much easier when you’re writing CSS.</p>
<h3 id="heading-the-box-model-and-why-you-need-box-sizing-border-box"><strong>The Box Model (and Why You Need box-sizing: border-box)</strong></h3>
<p>This is one of those things where it’s just really important to do this in every file you ever work in. Start your CSS with this:</p>
<pre><code class="lang-javascript">* {
  box-sizing: border-box;
}
</code></pre>
<p>The star selector means “select everything.” Now, over time you’re also going to start using pseudo-elements (don’t worry if you don’t know what those are yet, we’ll talk about them later), and when you do, you’ll want to update this to:</p>
<pre><code class="lang-javascript">*, *::before, *::after {
  box-sizing: border-box;
}
</code></pre>
<p>Just get in the habit of including the pseudo-elements now, even if you’re not using them yet, because you’re going to need them eventually.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765625804848/3db161f3-3700-44b2-8ece-51cf9804f3a1.webp" alt class="image--center mx-auto" /></p>
<p>Here’s why this matters. Let’s say you have an element and you give it a width of 400 pixels and padding of 20 pixels. The default behavior (called <code>content-box</code>) means that width is just the content itself, so you're adding 20 pixels on the left and 20 pixels on the right on top of that 400 pixels. Your element is actually 440 pixels wide now.</p>
<p>With <code>box-sizing: border-box</code>, that 400 pixels includes the padding. The padding pushes inward, and the element stays 400 pixels wide. This makes things much easier to calculate and to really be able to gauge how big something will be.</p>
<p>This isn’t as important as it used to be in the old days when we had float-based layouts and widths and heights were much more prevalent, but there’s still things where we set explicit widths and this is going to save you a lot of trouble in the long run. Just get in the habit of putting this at the top of every CSS file you create.</p>
<h3 id="heading-specificity-the-reason-your-styles-arent-working">Specificity (The Reason Your Styles Aren’t Working)</h3>
<p>Specificity is how specific our selectors are in our CSS, and it’s probably the number one reason beginners get frustrated when their styles don’t apply.</p>
<p>There tends to be three levels of selectors:</p>
<p><strong>Element selectors</strong> (lowest specificity):</p>
<pre><code class="lang-javascript">h2 {
  <span class="hljs-attr">color</span>: red;
}
</code></pre>
<p><strong>Class selectors</strong> (medium specificity):</p>
<pre><code class="lang-javascript">.color-accent {
  <span class="hljs-attr">color</span>: purple;
}
</code></pre>
<p><strong>ID selectors</strong> (highest specificity):</p>
<pre><code class="lang-javascript">#example {
  <span class="hljs-attr">color</span>: lime;
}
</code></pre>
<p>Here’s the thing: even if you have an h2 selector lower down in your CSS file that says the color should be red, if that h2 has a class on it with a different color, the class will win. It doesn’t matter where it is in the cascade because a class selector has more importance than an element selector.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765625892358/890877ee-8ce8-4d4b-9dd8-331440ea67a8.webp" alt class="image--center mx-auto" /></p>
<p>The same goes for IDs, an ID selector will always beat a class selector, which will always beat an element selector.</p>
<p>You can also boost specificity with descendant selectors. For example:</p>
<pre><code class="lang-javascript">.dark-background h3 {
  <span class="hljs-attr">color</span>: red;
}
</code></pre>
<p>This is more specific than just <code>h3</code> because it's a class selector and an element selector combined together.</p>
<p>When something isn’t working, your dev tools can really help you out. Right-click on the element, inspect it, and you’ll see all the styles being applied. The ones that are crossed out are being overridden, and you can see exactly why, what selector is winning and where it’s coming from in your CSS file.</p>
<p>In general, try to avoid too much nesting and overly specific selectors. A lot of design systems use single class selectors for good reason, they keep specificity manageable and predictable.</p>
<h3 id="heading-inheritance-write-less-css-by-letting-things-flow-down">Inheritance (Write Less CSS by Letting Things Flow Down)</h3>
<p>Inheritance is when properties are passed down from a parent element to its children and grandchildren. This is one of those things you hear about early on but then you forget about it or you don’t really understand the implications of it.</p>
<p>Here’s the key: anything related to typography inherits by default. This includes color, font-family, font-size, text-align, line-height, and so on. Anything that is not related to typography generally does not inherit.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765625944295/a47926bf-251e-4aca-a479-7868bdba0716.webp" alt class="image--center mx-auto" /></p>
<p>This means you can set styles once on the body (or html element) and they’ll flow down to everything inside:</p>
<pre><code class="lang-javascript">body {
  <span class="hljs-attr">color</span>: #<span class="hljs-number">333</span>;
  font-size: <span class="hljs-number">1.25</span>rem;
  font-family: Arial, sans-serif;
}
</code></pre>
<p>Now all your paragraphs, headings, and other text elements will inherit these styles. You don’t have to select each one individually.</p>
<p>The big advantage here is you get to write a lot less code. You set it once and then you don’t have to worry about it again. Of course, you can always overwrite things with more specific selectors when you need to.</p>
<p>One quick note: form elements don’t actually inherit font properties like you’d expect them to. You’ll often see this in CSS resets:</p>
<pre><code class="lang-javascript">button, input, textarea, select {
  <span class="hljs-attr">font</span>: inherit;
}
</code></pre>
<p>This forces these elements to start inheriting all the font properties like you would expect them to in the first place. The <code>font: inherit;</code> is a shorthand that inherits font-family, font-size, font-weight, line-height, and all the other font-related properties at once.</p>
<p>As much as possible, rely on inheritance. It means you get to write a lot less code and you can pick and choose places where you want to break out of that. One of the places where people go wrong is they start selecting everything and trying to style everything individually, and it just creates so much more work for you.</p>
<h3 id="heading-css-units-getting-the-right-size-for-the-job">CSS Units (Getting the Right Size for the Job)</h3>
<p>Understanding different units is fundamental for creating layouts that work across different screen sizes and situations. There are a lot of different units in CSS, and knowing which one to use can be confusing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765626005079/e710d22a-37f8-4b1b-8993-a733679e02fc.webp" alt class="image--center mx-auto" /></p>
<p><strong>Absolute units:</strong></p>
<ul>
<li><code>px</code> - Pixels are fixed units. Good for borders and small, precise measurements, but not great for responsive design when used for layout.</li>
</ul>
<p><strong>Relative units:</strong></p>
<ul>
<li><p><code>%</code> - Percentage of the parent element's size. Great for widths.</p>
</li>
<li><p><code>em</code> - Relative to the font-size of the element itself. Compounds when nested (can be tricky).</p>
</li>
<li><p><code>rem</code> - Relative to the root (html) font-size. Doesn't compound, making it more predictable. Great for spacing and font sizes.</p>
</li>
<li><p><code>vw/vh</code> - Viewport width and height. 1vw is 1% of the viewport width. Great for full-screen sections.</p>
</li>
</ul>
<p>For beginners, here’s a simple starting point:</p>
<ul>
<li><p>Use <code>rem</code> for font sizes and spacing (padding, margin)</p>
</li>
<li><p>Use <code>%</code> or <code>fr</code> (in grid) for widths</p>
</li>
<li><p>Use <code>px</code> for small things like borders</p>
</li>
<li><p>Use <code>vw/vh</code> when you need something relative to the viewport</p>
</li>
</ul>
<p>The reason <code>rem</code> is so popular is because if a user changes their browser's default font size (for accessibility), everything scales proportionally. If you used <code>px</code> everywhere, nothing would scale.</p>
<p>You don’t need to memorize all of this right away. Start with <code>rem</code> for most things and <code>px</code> for borders, and you'll be in good shape. As you get more comfortable, you can experiment with the other units.</p>
<h3 id="heading-display-property-how-elements-actually-behave">Display Property (How Elements Actually Behave)</h3>
<p>The display property is fundamental to understanding how elements behave on the page. Every HTML element has a default display value, and understanding this is crucial.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765626121022/03882ed0-dfc6-4e6c-b209-946a048b94dd.webp" alt class="image--center mx-auto" /></p>
<p><strong>display: block</strong> Block elements take up the full width available and start on a new line. Think of divs, paragraphs, headings, they stack vertically. You can set width and height on block elements.</p>
<p><strong>display: inline</strong> Inline elements only take up as much width as they need and don’t start on a new line. Think of spans, links, strong tags, they flow within text. You can’t set width and height on inline elements.</p>
<p><strong>display: inline-block</strong> This is a hybrid, it flows inline like an inline element, but you can set width and height on it like a block element. Really useful for things like navigation items or buttons that need to sit next to each other but have specific dimensions.</p>
<p><strong>display: none</strong> This removes the element from the page completely, it doesn’t take up any space. Different from <code>visibility: hidden</code> which hides it but leaves a gap where it would be.</p>
<p><strong>display: flex and display: grid</strong> These are your layout powerhouses. We’ll talk more about them in the next section.</p>
<p>Understanding display is important because sometimes you need to change an element’s default behavior. Maybe you want a link to behave like a block so you can give it padding and make it easier to click. Or you want list items to sit next to each other instead of stacking.</p>
<h3 id="heading-pseudo-classes-and-pseudo-elements-making-things-interactive">Pseudo-classes and Pseudo-elements (Making Things Interactive)</h3>
<p>Pseudo-classes and pseudo-elements are incredibly powerful tools that let you style elements based on their state or add content without touching your HTML. They look similar but do different things, and the way you write them is slightly different too.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765626184194/1bd2a922-eac3-47fe-8b63-6c99f41b0757.webp" alt class="image--center mx-auto" /></p>
<p><strong>Pseudo-classes</strong> use a single colon (<code>:</code>) and are all about state. They let you style elements when something happens to them:</p>
<pre><code class="lang-javascript">a:hover {
  <span class="hljs-attr">color</span>: blue;
  text-decoration: underline;
}
</code></pre>
<pre><code class="lang-javascript">button:focus {
  <span class="hljs-attr">outline</span>: <span class="hljs-number">2</span>px solid blue;
}input:invalid {
  border-color: red;
}li:first-child {
  font-weight: bold;
}
</code></pre>
<p>These are essential for creating interactive experiences. Your links need hover states, your form inputs need focus styles for accessibility, and you often want to style the first or last item in a list differently.</p>
<p><strong>Pseudo-elements</strong> use a double colon (<code>::</code>) and let you add decorative content or style specific parts of an element:</p>
<pre><code class="lang-javascript">.quote::before {
  <span class="hljs-attr">content</span>: <span class="hljs-string">'"'</span>;
  font-size: <span class="hljs-number">2</span>em;
  color: gray;
}
</code></pre>
<pre><code class="lang-javascript">p::first-line {
  font-weight: bold;
}.card::after {
  <span class="hljs-attr">content</span>: <span class="hljs-string">''</span>;
  display: block;
  width: <span class="hljs-number">100</span>%;
  height: <span class="hljs-number">3</span>px;
  background: blue;
  margin-top: <span class="hljs-number">1</span>rem;
}
</code></pre>
<p>The <code>::before</code> and <code>::after</code> pseudo-elements are particularly useful for adding decorative elements without cluttering your HTML. You can create icons, dividers, or visual effects purely with CSS.</p>
<p>One thing to remember: pseudo-elements need the <code>content</code> property to show up, even if it's just <code>content: ''</code>. Without it, they won't render at all.</p>
<p>And here’s why back in the box model section I included <code>*::before</code> and <code>*::after</code> in the box-sizing rule - pseudo-elements create actual boxes on the page that need the same box-sizing behavior as everything else. If you don't include them, you might run into weird sizing issues later on.</p>
<h3 id="heading-responsive-design-with-media-queries-making-it-work-everywhere">Responsive Design with Media Queries (Making It Work Everywhere)</h3>
<p>Your website needs to work on phones, tablets, laptops, and big desktop monitors. That’s just reality these days. And the way we make that happen is with media queries.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765626313373/ecbfcf06-671e-491a-91b0-8e08c9cfa7a4.webp" alt class="image--center mx-auto" /></p>
<p>Media queries let you apply different styles based on screen size:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* Mobile-first approach - styles for small screens first */</span>
.container {
  <span class="hljs-attr">padding</span>: <span class="hljs-number">1</span>rem;
}
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">/* Tablets and up */</span>
@media (min-width: <span class="hljs-number">768</span>px) {
  .container {
    <span class="hljs-attr">padding</span>: <span class="hljs-number">2</span>rem;
  }
}<span class="hljs-comment">/* Desktop and up */</span>
@media (min-width: <span class="hljs-number">1024</span>px) {
  .container {
    <span class="hljs-attr">padding</span>: <span class="hljs-number">3</span>rem;
    max-width: <span class="hljs-number">1200</span>px;
    margin: <span class="hljs-number">0</span> auto;
  }
}
</code></pre>
<p>I recommend a <strong>mobile-first approach</strong>. Write your base styles for mobile devices, then use <code>min-width</code> media queries to add complexity as the screen gets bigger. This makes more sense because:</p>
<ul>
<li><p>Mobile is the most constrained environment — if it works on mobile, you can build up from there</p>
</li>
<li><p>It’s easier to add complexity than to strip it away</p>
</li>
<li><p>Most traffic these days is mobile anyway</p>
</li>
</ul>
<p>You can also use media queries for other things:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* Dark mode */</span>
@media (prefers-color-scheme: dark) {
  body {
    <span class="hljs-attr">background</span>: #<span class="hljs-number">222</span>;
    color: #fff;
  }
}
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">/* Print styles */</span>
@media print {
  nav, footer {
    <span class="hljs-attr">display</span>: none;
  }
}
</code></pre>
<p>Common breakpoints you’ll see are:</p>
<ul>
<li><p>640px or 768px for tablets</p>
</li>
<li><p>1024px or 1280px for desktop</p>
</li>
<li><p>But honestly, your breakpoints should be based on your content, not specific devices</p>
</li>
</ul>
<p>Don’t stress too much about getting the perfect breakpoints from the start. As you build, you’ll see where your design breaks and that’s where you add a media query. Your browser dev tools let you test this easily — just toggle the responsive design mode and resize the viewport to see where things start looking wonky.</p>
<p>You don’t need to master responsive design right away. Start with making things work on mobile, then add a breakpoint or two as you need them. Over time you’ll get a feel for where you typically need to adjust things.</p>
<h2 id="heading-css-flexbox">CSS Flexbox</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737452849028/de3da275-1c62-4527-924c-a9fd419663e0.jpeg" alt class="image--center mx-auto" /></p>
<p>Check out <a target="_blank" href="https://levelup.gitconnected.com/learn-css-flexbox-the-easy-way-27bd01922040">this article</a> to explore the details.</p>
<p><a target="_blank" href="https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/">https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/6-flexbox-secrets-that-professional-css-developers-use-but-never-document-34c8e28d32be">https://javascript.plainenglish.io/6-flexbox-secrets-that-professional-css-developers-use-but-never-document-34c8e28d32be</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/5-flexbox-bugs-every-beginner-creates-and-how-to-spot-them-in-10-seconds-c8da0a82fcc5">https://levelup.gitconnected.com/5-flexbox-bugs-every-beginner-creates-and-how-to-spot-them-in-10-seconds-c8da0a82fcc5</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/the-flexbox-gaps-that-break-mobile-layouts-and-3-lines-of-css-to-fix-them-cd4c5c4ba851">https://javascript.plainenglish.io/the-flexbox-gaps-that-break-mobile-layouts-and-3-lines-of-css-to-fix-them-cd4c5c4ba851</a></p>
<p><a target="_blank" href="https://medium.com/@orami98/10-css-layouts-that-solve-the-most-frustrating-web-design-problems-in-2025-4e04608e7913">https://medium.com/@orami98/10-css-layouts-that-solve-the-most-frustrating-web-design-problems-in-2025-4e04608e7913</a></p>
<p><a target="_blank" href="https://medium.com/@kp9810113/stop-fighting-flexbox-7-simple-tricks-for-flawless-layouts-059758bd07f8">https://medium.com/@kp9810113/stop-fighting-flexbox-7-simple-tricks-for-flawless-layouts-059758bd07f8</a></p>
<h2 id="heading-css-grid">CSS Grid</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737460009209/2c50685a-9ad9-48f8-80ab-eb8302a16a14.png" alt class="image--center mx-auto" /></p>
<p>Check out <a target="_blank" href="https://www.freecodecamp.org/news/complete-guide-to-css-grid/">this handbook</a> to explore everything about Grid CSS.</p>
<p><a target="_blank" href="https://www.joshwcomeau.com/css/interactive-guide-to-grid/?ref=dailydev#grid-flow-2">https://www.joshwcomeau.com/css/interactive-guide-to-grid/?ref=dailydev#grid-flow-2</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/5-modern-css-grid-techniques-that-will-transform-your-layouts-b9f5ccbde9c2">https://javascript.plainenglish.io/5-modern-css-grid-techniques-that-will-transform-your-layouts-b9f5ccbde9c2</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/build-a-modern-dashboard-4-css-grid-techniques-for-complex-layouts-88cb5a90c34f">https://javascript.plainenglish.io/build-a-modern-dashboard-4-css-grid-techniques-for-complex-layouts-88cb5a90c34f</a></p>
<p><a target="_blank" href="https://medium.com/codetodeploy/7-modern-css-grid-tricks-i-wish-i-knew-earlier-especially-for-mobile-6b10d0154964">https://medium.com/codetodeploy/7-modern-css-grid-tricks-i-wish-i-knew-earlier-especially-for-mobile-6b10d0154964</a></p>
<h2 id="heading-the-css-revolution-is-here">The CSS Revolution is Here</h2>
<p>I will admit it — CSS used to feel like a quiet kid in the room. Useful, essential, but not exactly surprising. Then 2025 hit, and everything changed.</p>
<p>Over the past few months, I have been implementing some of these new features in a real-world freelance project, and I can tell you: We are living through a real CSS revolution.</p>
<p>If you are a Front-end developer, a no-code designer, or a freelance pro looking to deliver clean, modern, accessible interfaces, this is the moment to uplevel your toolkit.</p>
<p>Want to stick a header that just works without JavaScript?</p>
<p>Need to animate a button only when it’s inside a specific block?</p>
<p>Or maybe style elements differently depending on what’s inside them?</p>
<p>All of that is now possible — with CSS alone.</p>
<h3 id="heading-aspect-ratio"><code>aspect-ratio</code></h3>
<p>Have you ever used a “<a target="_blank" href="https://css-tricks.com/aspect-ratio-boxes/">padding hack</a>“ to force an aspect ratio such as 16:9 video embeds? As of September 2021, the <code>aspect-ratio</code> property is stable in evergreen browsers and is the only property needed to define an aspect ratio.</p>
<p>For an HD video, you can just use an <code>aspect-ratio: 16/9</code>. For a perfect square, only <code>aspect-ratio: 1</code> is required since the implied second value is also 1;</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737193884357/7181ee72-341c-4c85-8316-60406f1e4c94.png" alt class="image--center mx-auto" /></p>
<p>Of note, an applied <code>aspect-ratio</code> is forgiving and will allow context to take precedence. This means that when content causes the element to exceed the ratio in at least one dimension, the element will still grow or change shape to accommodate the content. To prevent or control this behavior, you can add additional dimension properties, like <code>max-width</code>, which may be necessary to avoid expanding out the flex or grid container.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737194543745/a4312664-bf17-460b-a43b-a89c08ceda37.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-object-fit"><code>object-fit</code></h3>
<p>This is actually the oldest property on this list, but it solves an important issue and definitely fits the sentiment of a one-line upgrade.</p>
<p>The use of <code>object-fit</code> causes an image or other replaced elements to act as the container for its content, and have those contents adopt resizing behavior similar to <code>background-size</code>.</p>
<p>While there are a few values available for <code>object-fit</code>, the following are the ones you are most likely to use:</p>
<ul>
<li><p><code>cover</code> - The image is resized to cover the element and maintain its aspect ratio so that the content is not distorted.</p>
</li>
<li><p><code>scale-down</code>: The image resizes (if needed) within the element so that it is fully visible without being clipped and maintains its aspect ratio, which may lead to extra space (“letterboxing”) around the image if the image has a different rendered aspect ratio.</p>
</li>
</ul>
<p>In either case, <code>object-fit</code> is an excellent property pairing with <code>aspect-ratio</code> to ensure images are not distorted when you apply a custom aspect ratio.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737195806752/8be7ca6b-f081-4761-b264-9909c3af72c9.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-margin-inline"><code>margin-inline</code></h3>
<p>One of many logical properties, <code>margin-inline</code> functions as a shorthand for setting the margin inline (left and right in horizontal writing modes).</p>
<p>The replacement here is simple:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Before */</span>
<span class="hljs-selector-tag">margin-left</span>: <span class="hljs-selector-tag">auto</span>;
<span class="hljs-selector-tag">margin-right</span>: <span class="hljs-selector-tag">auto</span>;

<span class="hljs-comment">/* After */</span>
<span class="hljs-selector-tag">margin-inline</span>: <span class="hljs-selector-tag">auto</span>;
</code></pre>
<p>Logical properties have been available for a couple of years and now have <a target="_blank" href="https://caniuse.com/css-logical-props">support upwards of 98%</a> (with occasional prefixing). Review the article by Ahmad Shadeed to learn more about <a target="_blank" href="https://ishadeed.com/article/css-logical-properties/">using logical properties</a> and their importance for sites with international audiences.</p>
<h3 id="heading-text-underline-offset"><code>text-underline-offset</code></h3>
<p>The use of text-underline-offset allows you to control the distance between the text baseline and the underline. This property has become a part of my standard reset, applied as follows:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-attr">[class]</span>) {
    <span class="hljs-attribute">text-underline-offset</span>: <span class="hljs-number">0.25em</span>;
}
</code></pre>
<p>This offset can clear descenders and (subjectively) improve legibility, particularly when links are grouped in close proximity, such as in a bulleted list.</p>
<p>This upgrade may replace older hacks like a border or pseudo-element or give a gradient background, especially when used with its friend:</p>
<ul>
<li><p><code>text-decoration-color</code>: to change the underlying color</p>
</li>
<li><p>t<code>ext-decoration-thickness</code>: to change the underlined stroke thickness</p>
</li>
</ul>
<h3 id="heading-outline-offset"><code>outline-offset</code></h3>
<p>Have you been using <code>box-shadow</code> or perhaps a pseudo-element to supply a custom outline when you wanted distance between the element and outline on focus?</p>
<p>Good news! The long-available <code>outline-offset</code> property may be the one you missed, and it enables pushing the outline away from the element with the positive value or pulling it into the element with the negative value.</p>
<p>In the demo, the gray solid line is the element border, and the blue dashed line is the outline being positioned via <code>outline-offset</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737198257542/620c04a9-955d-4705-b65f-806b481052fb.png" alt class="image--center mx-auto" /></p>
<p><strong>Reminder</strong>: Outlines are not computed as parts of the element’s box size, so increasing the distance will not increase the amount of space an element occupies. This is similar to how <code>box-shadow</code> is rendered without impacting the element size as well.</p>
<h3 id="heading-scroll-margin-topbottom">scroll-margin-top/bottom</h3>
<p>The <code>scroll-margin</code> set of properties (and corresponding <code>scroll-padding</code>) allows adding an offset to an element in the context of the scroll position. In other words, adding <code>scroll-padding-top</code> can increase the scroll offset above the element but doesn’t affect its layout position within the document.</p>
<p>Why is this useful? Well, it can alleviate issues caused by a sticky nav element covering content when an anchor link is activated. Using <code>scroll-margin-top</code> we can increase the space above the element when it is scrolled via navigation to account for the space occupied by the sticky nav.</p>
<p>If you have a navigation bar and an anchor link, the bar might obscure the target element. You can use <code>scroll-margin-top</code> to account for the height of the sticky header.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"sticky-header"</span>&gt;</span>Header<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"section1"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"scroll-target"</span>&gt;</span>Section 1<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">.sticky-header</span> {
  <span class="hljs-attribute">position</span>: sticky;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">color</span>: white;
}

<span class="hljs-selector-class">.scroll-target</span> {
  <span class="hljs-attribute">scroll-margin-top</span>: <span class="hljs-number">50px</span>; <span class="hljs-comment">/* Adds space equal to the sticky header's height */</span>
}
</code></pre>
<p>When navigating to #section1, it will appear 50px below the top of the viewport, leaving space for the sticky header.</p>
<h3 id="heading-color-scheme"><code>color-scheme</code></h3>
<p>You may be familiar with the <code>prefers-color-scheme</code> media query to customize dark and light themes. The CSS property <code>color-scheme</code> is an opt-in to adapting browser UI elements, including form controls, scrollbars, and CSS system colors. The adaptation asks the browser to render those items with either a <code>light</code> or <code>dark</code> scheme, and the property allows defining a preference order.</p>
<p>If you’re enabling the adaptation of your entire application, set the following <code>:root</code>, which says to preference a <code>dark</code> theme (or flip the order to preference a <code>light</code> theme).</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-attribute">color-scheme</span>: dark light;
}
</code></pre>
<p>You can also define <code>color-scheme</code> on individual elements, such as adjusting form controls within an element with a dark background to improve contrast.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.dark-background</span> {
    <span class="hljs-attribute">color-scheme</span>: dark;
}
</code></pre>
<h3 id="heading-width-fit-content"><code>width: fit-content</code></h3>
<p>One of my favorite CSS hidden gems is the use of fit-content to “shrink wrap“ an element to its content.</p>
<p>Whereas you may have used an inline display value such as <code>display: inline-block</code> to reduce an element’s width to the content size, an upgrade to <code>width: fit-content</code> will achieve the same effect. The advantage of <code>width: fit-content</code> is that it leaves the <code>display</code> value available, thereby not changing the position of the element in the layout unless you adjust that as well. The computed box size will adjust to the dimensions created by <code>fit-content</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737202564537/1c0ae2d6-5420-4bee-9be3-146c6227762e.png" alt class="image--center mx-auto" /></p>
<p>Consider the secondary upgrade for this technique to the logical property equivalent of <code>inline-size: fit-content</code>.</p>
<h3 id="heading-overscroll-behavior"><code>overscroll-behavior</code></h3>
<p>The default behavior of contained scroll regions - areas with limited dimensions where overflow is allowed to be scrolled - is that when the scroll runs out in the element, the scroll interaction passes to the background page. This can be jarring at best and frustrating at worst for your users.</p>
<p>Use of <code>overscroll-behavior: contain</code> will isolate the scrolling to the contained region, preventing the scroll by moving it to the parent page once the scroll boundary is reached. This is useful in contexts such as a sidebar of navigation links, which may have an independent scroll from the main page content, which may be a long article or documentation page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737203092051/d32261ff-ec0e-4298-9657-0e020e96d9ae.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-object-position"><code>object-position</code></h3>
<p>When you apply it to the image <code>object-fit</code> - It will crop the image to the specified height &amp; width in order to look sharp:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737276678130/85118fc2-8f8a-496d-a58c-44af4b952818.png" alt class="image--center mx-auto" /></p>
<p>However, we can’t control which part of the image will be cropped, so the object position is crucial.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.test</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">350px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">500px</span>;
  <span class="hljs-attribute">object-fit</span>: cover;
  <span class="hljs-attribute">object-position</span>: bottom;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737276790644/10a41502-5c12-44c7-8c2c-29241c04d03c.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-css"><span class="hljs-selector-tag">object-position</span>: <span class="hljs-selector-tag">top</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737276829280/34f6efaa-218d-439e-a192-6ed40e329a8e.png" alt class="image--center mx-auto" /></p>
<p>As well as we can add: left or right. We can even be more precise when we specify two parameters like <code>object-position: center bottom</code>;</p>
<h3 id="heading-supports"><strong>supports</strong></h3>
<p>The <code>@supports</code> rule in CSS is a feature-detection mechanism that allows developers to apply styles conditionally based on whether a specific CSS property is supported by the browser. This enables graceful degradation and progressive enhancement, ensuring that modern features are used when available while providing fallback styles for older browsers.</p>
<p><strong>How it works</strong>: The <code>@supports</code> rule checks if a given CSS property or feature is supported by the browser. If the condition evaluates to true, the enclosed styles are applied.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@supports</span> (<span class="hljs-attribute">display:</span> flex) {
  <span class="hljs-selector-class">.flex-container</span> &gt; * {
    <span class="hljs-attribute">text-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">2px</span> blue;
    <span class="hljs-attribute">float</span>: none;
  }
}
</code></pre>
<p>In this example, the styles inside <code>@supports</code> will only apply if the browser supports <code>display: flex</code>, ensuring a modern layout while avoiding issues in unsupported environments.</p>
<p><strong>Use Cases</strong>:</p>
<ul>
<li><p><strong>Progressive Enhancement</strong>: Apply modern styles while ensuring compatibility with older browsers.</p>
</li>
<li><p><strong>Failure Detection for New CSS Properties</strong>: Check support for advanced CSS properties like content-visibility or aspect-ratio.</p>
</li>
<li><p><strong>CSS Grid and Flexbox Fallbacks</strong>: Use @supports to apply grid or flexbox styles only when they are available while providing float-based fallbacks for older browsers.</p>
</li>
<li><p><strong>Ensuring Browser Compatibility</strong>: This helps maintain a consistent design experience across different user environments.</p>
</li>
</ul>
<h3 id="heading-content-visibility">content-visibility</h3>
<p>The <code>content-visibility</code> property is a game-changer for performance optimization in CSS. It enables browsers to skip the rendering work for an element until it’s needed, significantly improving the loading and rendering performance of complex or large layouts.</p>
<p><strong>How it works</strong>: When set to ‘auto’, <code>content-visibility</code> tells the browser that it can skip the rendering of the element’s content if they are not currently visible in the viewport. The browser still does the initial layout, but it doesn’t render the content until it’s needed.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">section</span> {
  <span class="hljs-attribute">content-visibility</span>: auto;
  <span class="hljs-attribute">contain-intrinsic-size</span>: auto <span class="hljs-number">500px</span>;
}
</code></pre>
<p>In this example, sections that are not in the viewport will not have their contents rendered, speeding up the initial page load. The <code>contain-intrinsic-size</code> property provides an estimated size for the content, helping to prevent layout shifts as the content is loaded.</p>
<p><strong>Use Cases:</strong></p>
<ul>
<li><p><strong>Long Lists and Feeds</strong>: Optimize the performance of infinite scrolling lists or news feeds by only rendering the items currently visible in the viewport.</p>
</li>
<li><p><strong>Complex layouts</strong>: Improved the initial load time of pages with complex layouts by deferring the rendering of off-screen sections until they are needed</p>
</li>
<li><p><strong>Tabs and Accordions</strong>: Prevent the browser from rendering the hidden tab panels or accordion sections until they are activated, improving initial page load and interactivity.</p>
</li>
<li><p><strong>Image-Heavy Pages:</strong> Combine <code>content-visibility: auto</code> with lazy-loading techniques to further optimize image loading and improve perceived performance.</p>
</li>
</ul>
<h3 id="heading-keyframes">keyframes</h3>
<p>The <code>@keyframes</code> rule is a cornerstone of CSS animations, allowing developers to define the intermediate steps in a CSS animation sequence. This powerful feature enables the creation of complex, multi-step animations without relying on JavaScript.</p>
<p><strong>How it works</strong>: <code>@keyframes</code> defines a series of style changes that should occur at specified points during an animation. These keyframes can be defined using percentages of the animation duration or the keywords ‘from‘ and ‘to’.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> slide-in {
  <span class="hljs-selector-tag">from</span> {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(-<span class="hljs-number">100%</span>);
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
  }

  50% {
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.5</span>;
  }

  <span class="hljs-selector-tag">to</span> {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">0</span>);
    <span class="hljs-attribute">opacity</span>: <span class="hljs-number">1</span>;
  }
}

<span class="hljs-selector-class">.animated-element</span> {
  <span class="hljs-attribute">animation</span>: slide-in <span class="hljs-number">2s</span> ease-in-out;
}
</code></pre>
<p>This example defines a ‘slide-in‘ animation where an element moves from left to right while fading in. The animation is then applied to <code>.animated-element</code>.</p>
<p><strong>Use cases:</strong></p>
<ul>
<li><p><strong>UI Transitions</strong>: Create smooth transitions for UI elements like modals, dropdowns, or navigation menus.</p>
</li>
<li><p><strong>Looping Animations</strong>: Design perpetual animations for loading indicators, background effects, or decorative elements.</p>
</li>
<li><p><strong>Interactive Feedback:</strong> Use animations triggered by user actions to provide user feedback and enhance user experience.</p>
</li>
<li><p><strong>Storytelling and Engagement</strong>: Develop complex, multi-step animations to guide users through the narrative or highlight key information on the page.</p>
</li>
</ul>
<h3 id="heading-image-set">image-set()</h3>
<p>The <code>image-set()</code> CSS functional notation is a powerful tool for responsive image management. It allows the browser to choose the most appropriate image from a set of options, primarily based on the device’s pixel density.</p>
<p><strong>How it works</strong>: <code>image-set()</code> provides a list of image sources along with their resolution descriptors. The browser then selects the most suitable image based on the device’s characteristics.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">200px</span>;
  <span class="hljs-attribute">background-repeat</span>: no-repeat;
  <span class="hljs-attribute">background-size</span>: cover;

  <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">image-set</span>(
    url(<span class="hljs-string">"https://image1.jpg"</span>) <span class="hljs-number">1</span>x,
    <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://image2.jpg"</span>) <span class="hljs-number">2</span>x
  );
</code></pre>
<p>In this example, devices with standard resolution will load <code>image1.jpg</code>, while high-resolution devices (like Retina displays) will load <code>image2.jpg</code>.</p>
<p><strong>Use Cases:</strong></p>
<ul>
<li><p><strong>Responsive Images</strong>: Provide different image resolutions for various device pixel ratios, ensuring crisp images on high-DPI screens without unnecessarily large downloads on standard screens</p>
</li>
<li><p><strong>Art Direction</strong>: Use <code>image-set()</code> in combination with media queries to serve different images based on both screen resolution and size, allowing for more nuanced art direction on responsive designs.</p>
</li>
<li><p><strong>Performance Optimization</strong>: By serving appropriately sized images, you can significantly reduce bandwidth usage and improve load times, especially on mobile devices.</p>
</li>
<li><p><strong>Future-Proofing</strong>: As new screen resolutions emerge, <code>image-set()</code> allows you to easily add support for these without changing your existing markup.</p>
</li>
</ul>
<h3 id="heading-white-space-collapse">white-space-collapse</h3>
<p>The <code>white-space-collapse</code> property offers precise control over how a whitespace is handled in text, allowing for collapsing, preserving, or other custom behaviors. This property provides more granular control than the traditional <code>white-space</code> property, enabling developers to fine-tune text presentation.</p>
<p><strong>How it works:</strong> <code>white-space-collapse</code> determines how sequences of white spaces are handled within an element. It offers several values:</p>
<ul>
<li><p>collapse: Collapses sequences of white space into a single space (default behavior)</p>
</li>
<li><p>preserve: Preserves all while space characters</p>
</li>
<li><p>preserve-breaks: Preserves line breaks but collapses other white spaces.</p>
</li>
<li><p>breaks-space: Similar to preserve but allows breaking at any white space character.</p>
</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-class">.collapsed-spaces</span> {
  <span class="hljs-attribute">white-space-collapse</span>: collapse;
}

<span class="hljs-selector-class">.preserved-spaces</span> {
  <span class="hljs-attribute">white-space-collapse</span>: preserve;
}

<span class="hljs-selector-class">.preserved-breaks</span> {
  <span class="hljs-attribute">white-space-collapse</span>: preserve-breaks;
}

<span class="hljs-selector-class">.break-spaces</span> {
  <span class="hljs-attribute">white-space-collapse</span>: break-spaces;
}
</code></pre>
<p>These examples demonstrate different ways of handling white space within text elements.</p>
<p><strong>Use Cases:</strong></p>
<ul>
<li><p><strong>Code Examples:</strong> Use preserve or preserve-breaks to display code snippets with accurate spacing and indentation.</p>
</li>
<li><p><strong>Preformatted Text:</strong> Maintain precise <code>whitespace</code> in preformatted text blocks, ensuring the layout matches the original formatting.</p>
</li>
<li><p><strong>Controlling Wrapping in Long Strings:</strong> Use <code>break-spaces</code> to allow wrapping within long strings that lack natural word breaks, such as URLs or database keys.</p>
</li>
<li><p><strong>Fine-Tuning Text Layout:</strong> Use collapse to control spacing between words and lines, creating more precise typographic adjustments.</p>
</li>
</ul>
<h3 id="heading-min-max-and-clamp">Min, Max, and Clamp</h3>
<h3 id="heading-min">min()</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">/* Keeps buttons from getting too wide on large screens */</span>
.pricing-button {
  width: min(<span class="hljs-number">300</span>px, <span class="hljs-number">90</span>%);
}
</code></pre>
<p>Think of <code>min()</code> as setting an upper limit. It will pick the smaller of the values. Handy for keeping elements from getting too big while still being responsive. So as long as <code>90%</code> calculates to be less than <code>300px</code> 90% is used; once it gets beyond <code>300px</code> that, the value is used.</p>
<h3 id="heading-max">max()</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">/* Ensures text stays readable even on tiny screens */</span>
.terms-container {
  font-size: max(<span class="hljs-number">16</span>px, <span class="hljs-number">1.2</span>vw);
}
</code></pre>
<p><code>max()</code> is like setting a minimum value, but it picks the larger option. Perfect for preventing elements from shrinking too much on mobile devices.</p>
<h3 id="heading-clamp"><strong>clamp()</strong></h3>
<p><code>clamp()</code> is like having <code>min()</code> and <code>max()</code> combined! It takes three values:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">320px</span>, <span class="hljs-number">90%</span>, <span class="hljs-number">1000px</span>);
  <span class="hljs-comment">/* additional recommendation */</span>
  <span class="hljs-attribute">margin</span>: auto;
}
</code></pre>
<p>Adding this one line will reduce the content size to occupy 90% of the viewport and limit its width between 320 and 1000 pixels (feel free to update the minimum and maximum values)</p>
<p>This change will automatically make your content look much nicer. It will no longer be a vast text block but something that looks more structured and organized. And if you also add <code>margin: auto</code> to the body, the content will be centered on the page. Two lines of code make the content look so much better.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737277421112/81e96c92-e282-4850-90f9-ecee317741f4.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-has-pseudo-class">The <code>:has()</code> pseudo-class</h3>
<pre><code class="lang-css"><span class="hljs-selector-class">.hero</span><span class="hljs-selector-pseudo">:has(.hero-button)</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--accent-<span class="hljs-number">50</span>);
}
</code></pre>
<p>This CSS pseudo-class <code>:has()</code> provides a powerful way to select an element based on its descendants, similar to the application of conditional styles.</p>
<h3 id="heading-is-amp-where-cleaner-dry-selectors"><code>:is()</code> &amp; <code>:where()</code> – Cleaner, DRY selectors</h3>
<p>Writing complex combinations of selectors has always been a pain. With <code>:is()</code> and <code>:where()</code>, we can group rules and make the code cleaner and more readable.</p>
<pre><code class="lang-typescript">:is(h1, h2, h3, h4) {
  font-family: <span class="hljs-string">"Inter"</span>, sans-serif;
}
</code></pre>
<p><code>:is()</code> applies the <strong>highest specificity</strong> of any selector inside.<br /><code>:where()</code> has <strong>zero specificity</strong>: perfect for resets or design systems.</p>
<p>💡 <strong>Example with a custom reset:</strong></p>
<pre><code class="lang-typescript">:where(h1, h2, h3, p) {
  margin-block: <span class="hljs-number">0.5</span>em;
}
</code></pre>
<p><strong>🛠️Use-case:</strong><br />When working with WordPress themes or CSS builders, these help you maintain style control without fighting the cascade.</p>
<h3 id="heading-backdrop-style-native-modal-backgrounds"><code>::backdrop</code> – Style native modal backgrounds</h3>
<p>Using <code>&lt;dialog&gt;</code> (HTML5), You can now <strong>style the background behind the modal</strong>, creating modern effects like blur or gradients.</p>
<pre><code class="lang-typescript">::backdrop {
  background: rgba(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.5</span>);
  backdrop-filter: blur(<span class="hljs-number">6</span>px);
}
</code></pre>
<p><em>Elegant and accessible native effect</em></p>
<p><strong>🛠️Use-case:</strong><br />Perfect for portfolio sites, contact modals, GDPR, or newsletter popups — without heavy plugins.</p>
<h3 id="heading-target-text-automatically-highlight-linked-text"><code>::target-text</code> – Automatically highlight linked text</h3>
<p>This new pseudo-class lets you <strong>style the text targeted by internal links</strong> (<code>#anchor</code>), improving navigation in long documents or FAQ sections.</p>
<pre><code class="lang-typescript">::target-text {
  background: yellow;
}
</code></pre>
<p><strong>🛠️Use-case:</strong><br />Great for documentation, anchor menu links, or e-commerce with expandable FAQ blocks.</p>
<h3 id="heading-container-queries">Container Queries</h3>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries">CSS container queries</a> introduced a new approach to responsiveness. Previously, we used media queries to create UIs that adapted to different screen sizes. But it wasn’t as easy as it sounds. There were issues in maintenance, performance, flexibility, and style overlapping.</p>
<p>Container queries resolve these issues by allowing developers to customize elements depending on their parent container size. Since this method doesn’t depend on the viewport size, it makes the HTML components fully modular and self-contained.</p>
<p>The following is a simple example of how container queries work:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.wrapper</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">2</span>fr <span class="hljs-number">1</span>fr;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
}
<span class="hljs-keyword">@container</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">500px</span>) {
  <span class="hljs-selector-class">.profile-card</span> {
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">150px</span> <span class="hljs-number">1</span>fr;
    <span class="hljs-attribute">grid-template-rows</span>: auto <span class="hljs-number">1</span>fr;
    <span class="hljs-attribute">align-items</span>: start;
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
  }

  <span class="hljs-selector-class">.profile-card</span> <span class="hljs-selector-tag">header</span>,
  <span class="hljs-selector-class">.profile-card</span> <span class="hljs-selector-class">.bio</span> {
    <span class="hljs-attribute">grid-column</span>: <span class="hljs-number">2</span>;
  }

  <span class="hljs-selector-class">.profile-card</span> <span class="hljs-selector-class">.profile-image</span> {
    <span class="hljs-attribute">grid-row</span>: <span class="hljs-number">1</span> / <span class="hljs-number">3</span>;
    <span class="hljs-attribute">grid-column</span>: <span class="hljs-number">1</span>;
  }
}
</code></pre>
<p>This container query adjusts the layout of the profile card when its width reaches 500px or more. It changes the card from a stacked layout (with the image on top) to a two-column layout when the image appears on the left and the text content aligns on the right.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737284839310/b9f47730-9a50-4c1e-a827-b64de2d2986d.png" alt class="image--center mx-auto" /></p>
<p>Container queries are very useful in design systems where components need to adapt based on their immediate environment rather than the entire viewport. However, container queries still <a target="_blank" href="https://caniuse.com/css-container-queries">lack full browser support</a>. If your users are using unsupported browsers or older versions, they might face styling issues.</p>
<h3 id="heading-subgrid">Subgrid</h3>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid">Subgrid</a> is an exciting addition to the CSS grid layout model. It allows you to inherit the grid structure of the parent grid container in child grid items. In other words, a subgrid allows you to align child elements according to the rows or columns of the parent grid. This method allows you to easily create complex nested grids without using nested grid overrides.</p>
<p>In the following code example, the layout uses the subgrid approach within a list:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.product-wrapper</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(auto-fit, minmax(<span class="hljs-number">300px</span>, <span class="hljs-number">1</span>fr));
}
<span class="hljs-selector-class">.product-card</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-rows</span>: subgrid; <span class="hljs-comment">/* Allows the nested grid to align directly with the parent grid */</span>
}
</code></pre>
<p>In the example, the <code>product-wrapper</code> creates a flexible grid layout to control the number of columns based on the container width. Then, each <code>product-card</code> aligns its rows directly with the grids defined by the <code>product-wrapper</code> .</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737285570041/3b758743-1a08-49e2-9778-39a9013bc46c.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-layer">@layer</h3>
<p>If you have used Tailwind CSS, this might look familiar. <code>@layer</code> manages specificity conflicts by explicitly ordering style groups. Later layers always “win” regardless of specificity, solving the cascade that confuses (and annoys!) so many developers.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/* Define layer order - order here determines priority */</span>
<span class="hljs-meta">@layer</span> reset, components, utilities;

<span class="hljs-comment">/* Reset layer: lowest priority */</span>
<span class="hljs-meta">@layer</span> reset {
  * {
    margin: <span class="hljs-number">0</span>;
    padding: <span class="hljs-number">0</span>;
    box-sizing: border-box;
  }
}

<span class="hljs-comment">/* Components layer: middle priority */</span>
<span class="hljs-meta">@layer</span> components {
  .button {
    <span class="hljs-comment">/* Even if utilities have lower specificity,
       they'll still override these styles */</span>
    padding: <span class="hljs-number">.5</span>rem <span class="hljs-number">1</span>rem;
    background: blue;
  }
}

<span class="hljs-comment">/* Utilities layer: highest priority */</span>
<span class="hljs-meta">@layer</span> utilities {
  .p<span class="hljs-number">-4</span> {
    <span class="hljs-comment">/* This wins over component padding */</span>
    padding: <span class="hljs-number">1.25</span>rem;
  }

  .bg-red {
    <span class="hljs-comment">/* This wins over component background */</span>
    background: red;
  }
}
</code></pre>
<h3 id="heading-scope">scope</h3>
<p>The <code>@scope</code> at-rule introduces a revolutionary way to manage CSS specificity and encapsulation. It allows developers to define a specific scope for CSS selectors, making it easier to target elements within particular DOM subtrees without affecting elements outside the scope.</p>
<p><strong>How it works</strong>: The <code>@scope</code> rule defines a boundary within which certain styles apply. This boundary is determined by a selector, and the styles within the <code>@scope</code> block only affect elements that match the selector and are descendants of the scoped element.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"my-component"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This paragraph is inside the scope.<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">p</span>&gt;</span>This paragraph is outside the scope.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
<span class="hljs-keyword">@scope</span> (#my-component) {
  <span class="hljs-selector-tag">p</span> {
    <span class="hljs-attribute">color</span>: blue;
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>In this example, only the paragraph inside the #my-component div will be colored blue. The paragraph outside remains unaffected.</p>
<p><strong>Use cases:</strong></p>
<ul>
<li><p><strong>Component-Based Architectures</strong>: <code>@scope</code> is the idea of styling components independently. Each component can have its own encapsulated styles, preventing conflicts between components and promoting code reuse.</p>
</li>
<li><p><strong>Third-party Libraries</strong>: Control the styling of third-party libraries or embedded widgets without worrying that their styles will affect your main application’s style.</p>
</li>
<li><p><strong>Scoped CSS Modules</strong>: While CSS Modules and other build-time solutions offer similar functionality,<code>@scope</code> brings this capability is brought natively to the browser, simplifying workflows and potentially improving performance.</p>
</li>
</ul>
<h3 id="heading-anchor-dynamically-position-elements-based-on-others"><code>anchor()</code> – Dynamically position elements based on others</h3>
<p>A brand-new CSS function that lets you <strong>anchor an element’s position</strong> (e.g. tooltip, menu) to another element, without JS.</p>
<pre><code class="lang-typescript">.tooltip {
  position: absolute;
  top: anchor(bottom);
  left: anchor(center);
}
</code></pre>
<p><strong>This changes the game for:</strong></p>
<ul>
<li><p>Tooltips</p>
</li>
<li><p>Dropdowns</p>
</li>
<li><p>Popovers</p>
</li>
</ul>
<p><strong>🛠️Use-case:</strong><br />Complex UI interactions (e.g., e-commerce filters, admin panels) <strong>without JavaScript</strong>.</p>
<h3 id="heading-accent-color"><code>accent-color</code></h3>
<p>If you have ever wanted to change the color of checkboxes or radio buttons, you have been seeking <code>accent-color</code>. With this property, you can modify the <code>:checked</code> the appearance of radio buttons or checkboxes and the filled-in states for both the progress element and range input. The browser’s default focus “halo“ may also be adjusted if you do not have another override.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737200674390/863f5f4c-3f05-4eb9-a035-6da3ac56f475.png" alt class="image--center mx-auto" /></p>
<p>Consider adding both <code>accent-color</code> and <code>color-scheme</code> to your baseline application styles for a quick win toward custom theme management.</p>
<h3 id="heading-light-dark-automatic-theme-switching-no-media-queries"><code>light-dark()</code> – Automatic theme switching, no media queries</h3>
<p>Want your components to automatically adapt to the system’s theme?</p>
<pre><code class="lang-typescript">body {
  color: light-dark(black, white);
  background-color: light-dark(white, black);
}
</code></pre>
<p><strong>✨Advantage:</strong><br />One color value that adapts automatically based on light or dark mode.</p>
<p><strong>🛠️Use-case:</strong><br />Custom themes for SaaS platforms, dashboards, or portfolio sites.</p>
<h3 id="heading-relative-color-syntax-amp-new-color-spaces">Relative color syntax &amp; new color spaces</h3>
<p>You can now use <strong>colors derived from other colors</strong>, creating flexible, adaptive palettes.</p>
<pre><code class="lang-typescript">color: rgb(<span class="hljs-keyword">from</span> <span class="hljs-keyword">var</span>(--primary-color) r g b / <span class="hljs-number">50</span>%);
</code></pre>
<p><strong>Supports</strong>:<br /><code>oklch</code>, <code>oklab</code>, <code>color-mix()</code>, <code>color-contrast()</code>.</p>
<p>💡 <strong>Example with</strong> <code>color-mix()</code><strong>:</strong></p>
<pre><code class="lang-typescript">color: color-mix(<span class="hljs-keyword">in</span> srgb, red <span class="hljs-number">30</span>%, blue);
</code></pre>
<p><strong>🛠️Use-case:</strong><br />Variable branding, automatic dark mode themes, or accessible UIs.</p>
<h3 id="heading-property-variables-get-smarter-with-property"><code>@property</code> - Variables get smarter with property</h3>
<p>CSS variables are powerful, but the new <code>@property</code> at-rule takes them to the next level.</p>
<p>Now, you can define custom properties with specific types, inheritance rules, and default values.</p>
<p>Before the <code>@property</code> at-rule, custom properties were powerful but lacked type safety and constraints. For example:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--rotation</span>: <span class="hljs-number">45deg</span>;
}
<span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">rotate</span>(var(--rotation));
}
</code></pre>
<p>This works, but the variable is essentially unregulated.</p>
<p>If someone accidentally assigns an invalid value like <code>—rotation: blue</code>, the code breaks or behaves unpredictably.</p>
<p>Now, you can declare custom properties with a defined syntax, initial value, and inheritance rules.</p>
<p>Here’s how it works:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@property</span> --rotation {
  <span class="hljs-selector-tag">syntax</span>: '&lt;<span class="hljs-selector-tag">angle</span>&gt;';
  <span class="hljs-selector-tag">inherits</span>: <span class="hljs-selector-tag">false</span>;
  <span class="hljs-selector-tag">initial-value</span>: 0<span class="hljs-selector-tag">deg</span>;
}
<span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">rotate</span>(var(--rotation));
}
</code></pre>
<ul>
<li><p><code>syntax</code>: Specifies the type of value the property can accept. For <code>--rotation</code>, it’s an <code>&lt;angle&gt;</code> (like <code>45deg</code> or <code>1turn</code>).</p>
</li>
<li><p><code>inherits</code>: Determines if the property should inherit its value from its parent element. In this case, we set it to <code>false</code>.</p>
</li>
<li><p><code>initial-value</code>: Sets a default value if no other value is assigned. Here, it defaults to <code>0deg</code>.</p>
</li>
</ul>
<h3 id="heading-color-contrast-automatic-accessibility-support"><code>color-contrast()</code> – Automatic accessibility support</h3>
<p>Want your text to always be readable no matter the background?</p>
<pre><code class="lang-typescript">color: color-contrast(white vs #<span class="hljs-number">000</span>, #<span class="hljs-number">0</span>f62fe, #f00);
</code></pre>
<p><strong>💪What it does:</strong><br />Chooses the color with the <strong>best contrast ratio</strong> against a background, meeting WCAG guidelines.</p>
<p><strong>🛠️Use-case:</strong><br />Accessible interfaces for public agencies, corporate sites, or B2B platforms.</p>
<h3 id="heading-contain-layout-avoid-global-layout-recalculations"><code>contain: layout</code> — Avoid Global Layout Recalculations</h3>
<p><strong>Problem:</strong> A small update triggers a full layout reflow. Performance drops.</p>
<p><strong>Fix:</strong></p>
<pre><code class="lang-typescript">.card {
  contain: layout;
}
</code></pre>
<p><strong>Why it helps:</strong> The browser isolates layout changes inside <code>.card</code>. No more cascading reflows.</p>
<p><strong>Result:</strong> Faster updates. Smoother interactions. Cleaner performance graphs.</p>
<h3 id="heading-pointer-events-none-control-what-gets-clicked"><code>pointer-events: none</code> — Control What Gets Clicked</h3>
<p><strong>Problem:</strong> An overlay element blocks interaction with elements underneath.</p>
<p><strong>Fix:</strong></p>
<pre><code class="lang-typescript">.floating-label {
  pointer-events: none;
}
</code></pre>
<p><strong>Why it helps:</strong> The element becomes visually present but non-interactive.</p>
<p><strong>Result:</strong> Users interact with what they see underneath.</p>
<h3 id="heading-backdrop-filter-elegant-blur-behind-overlays"><code>backdrop-filter</code> – Elegant blur behind overlays</h3>
<p>Want that “frosted glass” effect you see in macOS, iOS, or clean minimalist UIs? You can now create it natively with CSS.</p>
<pre><code class="lang-typescript">.modal {
  background: rgba(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0.6</span>);
  backdrop-filter: blur(<span class="hljs-number">12</span>px);
}
</code></pre>
<p>💡 <strong>Perfect for:</strong><br />Popups, sticky headers, modals, dropdowns with depth.</p>
<p><strong>🛠️Use-case:</strong><br />Elevates the UI in portfolios, landing pages, or SaaS interfaces.</p>
<h3 id="heading-wrap-headings-in-a-more-balanced-way">Wrap headings in a more balanced way</h3>
<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-selector-tag">h4</span>, <span class="hljs-selector-tag">h5</span>, <span class="hljs-selector-tag">h6</span> {
  <span class="hljs-attribute">text-wrap</span>: balance;
}
</code></pre>
<p>Headings are an essential part of the web structure, but due to their larger size and shorter content, they may look weird. Especially when they occupy more than one line. A solution that will help is balancing the headings with <code>text-wrap</code>.</p>
<p>Although balance seems to be the most popular value for <code>text-wrap</code>, it is not the only one. We could also use <code>pretty</code>, that moves an extra word to the last row if needed instead of balancing all the content. Unfortunately, <code>pretty</code> has yet to count onboard support.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737278117909/7d14e131-e932-4ba5-ba5f-d0614e4da341.png" alt class="image--center mx-auto" /></p>
<p>Balanced wrapping can improve visibility and readability.</p>
<h3 id="heading-font-size-adjust-better-legibility-with-fallback-fonts"><code>font-size-adjust</code> – Better legibility with fallback fonts</h3>
<p>Sometimes, fallback fonts have a different “x-height,” making text appear too large or too small. This property keeps visual consistency across fonts.</p>
<pre><code class="lang-typescript">body {
  font-size-adjust: <span class="hljs-number">0.5</span>;
}
</code></pre>
<p>🎯 <strong>Great when:</strong><br />You use Google Fonts with fallbacks like Helvetica or Arial.</p>
<p><strong>🛠️Use-case:</strong><br />Editorial sites, blogs, or documentation where text must remain clear even without the main font.</p>
<h3 id="heading-scrollbar-gutter-amp-scrollbar-color">Scrollbar-Gutter &amp; Scrollbar-Color</h3>
<p>When a browser displays a scrollbar, the layout can shift as space is taken up. With <code>scrollbar-gutter</code>, you can preserve scrollbar space even before scrolling begins:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.scrollable</span> {
  <span class="hljs-attribute">scrollbar-gutter</span>: stable both-edges;
}
</code></pre>
<p>You can also style your scrollbars with <code>scrollbar-color</code>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.scrollable</span> {
  <span class="hljs-attribute">scrollbar-color</span>: <span class="hljs-number">#444</span> <span class="hljs-number">#ccc</span>;
}
</code></pre>
<p>This ensures a consistent look and prevents layout jumps.</p>
<p><strong>What it good for ✅</strong></p>
<ul>
<li><p><code>scrollbar-gutter</code> keeps layouts stable by reserving space for a scrollbar, preventing annoying shifts when the scrollbar appears.</p>
</li>
<li><p><code>scrollbar-color</code> lets you style the scrollbar’s track and thumb, enhancing design consistency, especially for dark or themed UIs.</p>
</li>
</ul>
<h3 id="heading-transition-behavior">transition-behavior</h3>
<p>While <code>transition-timing-function</code> has served us well, <code>transition-behavior</code> introduces additional control over animations, such as reversing or pausing transitions without complex JavaScript. This paves the way for smoother UI interactions and advanced animation scenarios.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.card</span> {
  <span class="hljs-attribute">transition-property</span>: opacity, display;
  <span class="hljs-attribute">transition-duration</span>: <span class="hljs-number">0.25s</span>;
  <span class="hljs-attribute">transition-behavior</span>: allow-discrete;
}

<span class="hljs-selector-class">.card</span><span class="hljs-selector-class">.fade-out</span> {
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">display</span>: none;
}
</code></pre>
<p><strong>What it’s good for ✅</strong></p>
<ul>
<li><p>Expands on basic transitions to offer reversible or more complex transitions without heavy scripting.</p>
</li>
<li><p>Useful for refined UI effects, interactive components, and unique animation scenarios.</p>
</li>
</ul>
<h3 id="heading-starting-style-fixing-animation-start-issues">starting-style — Fixing animation Start Issues</h3>
<ul>
<li><p>Normally, when you hide an element (<code>display: none</code>), it pops up instantly when shown.</p>
</li>
<li><p><code>@starting-style</code> defines its initial state so transitions work smoothly.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-meta">@starting</span>-style {
  .modal {
    opacity: <span class="hljs-number">0</span>;
    transform: scale(<span class="hljs-number">0.8</span>);
  }
}

.modal {
  transition: opacity <span class="hljs-number">0.5</span>s, transform <span class="hljs-number">0.5</span>s;
}

.modal.show {
  opacity: <span class="hljs-number">1</span>;
  transform: scale(<span class="hljs-number">1</span>);
}
</code></pre>
<p>The modal fades in instead of appearing suddenly</p>
<p>✅ Chrome, Edge</p>
<p>❌ Not yet in Firefox or Safari</p>
<h3 id="heading-animation-composition-layer-multiple-animations"><code>animation-composition</code> – Layer multiple animations</h3>
<p>This property allows you to <strong>control how multiple animations combine</strong> on a single element:</p>
<pre><code class="lang-typescript">.element {
  animation: fadeIn <span class="hljs-number">1</span>s, slideIn <span class="hljs-number">1</span>s;
  animation-composition: accumulate;
}
</code></pre>
<p><strong>Modes:</strong></p>
<ul>
<li><p><code>replace</code> (default): one animation overrides the other</p>
</li>
<li><p><code>accumulate</code>: adds values</p>
</li>
<li><p><code>add</code>: combines effects into a single result</p>
</li>
</ul>
<p><strong>🛠️Use-case:</strong><br />Interactive components like dropdowns, sliders, or animated cards.</p>
<h3 id="heading-scroll-snap-type-section-by-section-scroll-control"><code>scroll-snap-type</code> – Section-by-section scroll control</h3>
<p>With scroll snapping, you can make sections or slides “snap” into place, providing a <strong>refined mobile UX</strong>.</p>
<pre><code class="lang-typescript">.container {
  scroll-snap-<span class="hljs-keyword">type</span>: y mandatory;
  overflow-y: scroll;
}
</code></pre>
<pre><code class="lang-typescript">.section {
  scroll-snap-align: start;
}
</code></pre>
<p><strong>🛠️Use-case:</strong><br />Horizontal carousels, galleries, full-page scroll sections — super mobile-friendly.</p>
<h3 id="heading-prefers-reduced-motion-respect-ux-accessibility"><code>prefers-reduced-motion</code> – Respect UX accessibility</h3>
<p>A media query that checks user settings and <strong>disables or simplifies motion effects</strong> when requested.</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@media</span> (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}
</code></pre>
<p>🧠 A must-have for every modern project, ensuring <strong>inclusive and responsible design</strong>.</p>
<p><strong>🛠️Use-case:</strong><br />Sites for public entities, healthcare, or simply smoother UX on slower devices.</p>
<h2 id="heading-css-content-values-master-min-content-max-content-and-fit-content-for-better-layouts">CSS Content Values: Master min-content, max-content, and fit-content for Better Layouts</h2>
<p><strong>You’re building a responsive layout and wrestling with width calculations. The content sometimes overflows, sometimes leaves too much whitespace, and media queries feel like duct tape holding everything together.</strong></p>
<p>Most developers stick to percentages, fixed pixels, or viewport units because that’s what they learned first. But there’s a more elegant approach hiding in plain sight.</p>
<p><strong>The problem:</strong> Traditional sizing methods force you to guess at content dimensions. You set <code>width: 300px</code> and hope the content fits, or use <code>width: 100%</code> and accept whatever space you get, regardless of whether it makes sense for the content.</p>
<p><strong>The solution:</strong> CSS content-based sizing values (<code>min-content</code>, <code>max-content</code>, <code>fit-content</code>) let your layouts adapt intelligently to actual content dimensions, creating interfaces that feel naturally responsive.</p>
<p>These values have been supported across modern browsers for years, yet most developers never use them. Once you understand how they work, you’ll see layout opportunities everywhere — from navigation menus that size themselves perfectly, to cards that adapt to their content, to forms that feel naturally proportioned.</p>
<p>Today, I’ll show you how these three values work, when to use each one, and 5 production-ready patterns that will change how you approach CSS layouts.</p>
<p>Check out <a target="_blank" href="https://medium.com/render-beyond/css-content-values-master-min-content-max-content-and-fit-content-for-better-layouts-0e4dff937e47">this article</a>.</p>
<p><a target="_blank" href="https://medium.com/@orami98/10-css-techniques-that-solve-the-most-frustrating-layout-problems-854ca79c7ecc">https://medium.com/@orami98/10-css-techniques-that-solve-the-most-frustrating-layout-problems-854ca79c7ecc</a></p>
<h2 id="heading-units">Units</h2>
<p>In CSS, there are two main types of units: absolute and relative. Absolute units like <code>cm</code>, <code>mm</code>, <code>in</code> (and others) represent fixed physical measurements and have been available since the early days of CSS. Pixels (<code>px</code>) are actually relative units (they scale based on the viewing device). Most other units are also relative, scaling based on fonts, viewports, or other factors. CSS1 gave us <code>em</code> for font-based sizing, CSS3 added viewport units like <code>vh</code> and <code>vw</code> (introduced around 2012), and recently (2022) we got <code>dvh</code> to handle mobile browsers better. Note that several relative units (like <code>em</code>, <code>ex</code>, <code>ch</code>) can compute differently based on where they’re used. Their behavior might change when used with <code>font-size</code> versus other properties like <code>width</code> or <code>margin</code>.</p>
<h3 id="heading-font-based">Font-based</h3>
<ul>
<li><p><strong>em</strong> - Relative to the parent element’s font size</p>
</li>
<li><p><strong>rem</strong> - Relative to the root element’s font size</p>
</li>
<li><p><strong>ex</strong> - Represents the x-height of the current font (roughly the height of lowercase “x”) - this unit has been around since CSS1 but I only recently really learned about it</p>
</li>
<li><p><strong>ch</strong> - Width of the “0” (zero) character in the current font - available since CSS3 but often overlooked</p>
</li>
<li><p><strong>lh</strong> - Equal to the line-height of the element</p>
</li>
</ul>
<h3 id="heading-viewport-based">Viewport-based</h3>
<ul>
<li><p><strong>vh</strong> - 1% of the viewport height</p>
</li>
<li><p><strong>vw</strong> - 1% of the viewport width</p>
</li>
<li><p><strong>vmin</strong> - 1% of the viewport’s smaller dimension (height or width) - also from CSS3 but less commonly used</p>
</li>
<li><p><strong>vmax</strong> - 1% of the viewport’s larger dimension (height or width) - also from CSS3 but less commonly used</p>
</li>
</ul>
<h3 id="heading-modern-viewport">Modern viewport</h3>
<ul>
<li><p><strong>dvh</strong> - Dynamic viewport height, adjusts for mobile browser chrome/UI elements</p>
</li>
<li><p><strong>dvw</strong> - Dynamic viewport width</p>
</li>
<li><p><strong>svh</strong> - Small viewport height, the smallest possible height when accounting for dynamic UI elements</p>
</li>
<li><p><strong>svw</strong> - Small viewport width</p>
</li>
<li><p><strong>lvh</strong> - Large viewport height, the largest possible height when accounting for dynamic UI elements</p>
</li>
<li><p><strong>lvw</strong> - Large viewport width</p>
</li>
</ul>
<p><a target="_blank" href="https://blog.stackademic.com/stop-using-100vh-on-mobile-use-these-new-css-units-instead-adf22e7a6ea9">https://blog.stackademic.com/stop-using-100vh-on-mobile-use-these-new-css-units-instead-adf22e7a6ea9</a></p>
<h2 id="heading-a-practical-migration-handbook-from-sassscss-to-modern-native-css">A practical migration handbook from SASS/SCSS to modern native CSS</h2>
<p>Modern CSS has rapidly evolved, integrating many features that were once exclusive to Sass/SCSS. Features like CSS variables, native nesting, color functions, and cascade layers are now built into the language, eliminating the need for a preprocessor in most cases.</p>
<p><a target="_blank" href="https://medium.com/@karstenbiedermann/a-practical-migration-handbook-from-sass-scss-to-modern-native-css-be5d3f50d2ac">This article</a> provides a practical guide for developers looking to migrate their codebase from SCSS/Sass to modern native CSS.</p>
<h2 id="heading-these-3-css-breakpoints-handle-95-of-your-layouts">These 3 CSS breakpoints handle 95% of your layouts</h2>
<p>Most of us aren’t designing interfaces for smart fridges, VR headsets, and a wristwatch all at once. And yet, devs (especially early career ones) spend way too much time micromanaging media queries like they are twerking the shields on the rocket lunch.</p>
<p>You don’t need 12 breakpoints. You only need three.</p>
<h3 id="heading-the-problem-too-many-breakpoints-too-little-gain">The Problem: Too many breakpoints, too little gain.</h3>
<p>You know the drill. You start a project, install Taiwind or write a custom media query setup, and then…</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*XmI0WUG0XdxD4RQQLOOSgA.png" alt /></p>
<p>By the time you finish typing, the site is already outdated.</p>
<p>You are trying to catch every edge case, but you are drowning the the maintenance hell.</p>
<p>And guess what? Your users don’t care.</p>
<p>They just want the site to <em>look good</em> and <em>work</em> on their phone, tablet, and laptop.</p>
<h3 id="heading-the-3-breakpoints-that-work-for-95-of-projects">The 3 breakpoints that work for 95% of projects</h3>
<p>If you want a setup that’s <em>practical, predictable</em>, and <em>future-proof</em>, start here:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*iWFF3hchYMLeto25zGjvdg.png" alt /></p>
<p>That’s it.</p>
<p><strong>The logic behind these:</strong></p>
<ul>
<li><p><code>0 - 767px</code> → Phones (the smallest view, default)</p>
</li>
<li><p><code>768px - 1023px</code> → Tablets (or awkward in-between devices)</p>
</li>
<li><p><code>1024px and up</code> → Desktops, laptops, and beyond</p>
</li>
</ul>
<p>If you really <em>need</em> a wider breakpoint (say for ultra-wide monitors), go ahead and add a <code>1280px</code> or <code>1440px</code>. But don’t start there. Wait until <strong>the design demands it</strong>, not your anxiety.</p>
<p>And if you’re using a framework like <strong>Tailwind</strong>, you’re already covered:</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*35Fm-i6s7IXsVOlhu01JHg.png" alt /></p>
<p>Use <code>md</code>, <code>lg</code>, and <code>xl</code>, and you’re done. Don’t fight the framework.</p>
<h2 id="heading-responsive-tables-are-hard-heres-a-pattern-that-works">Responsive Tables are Hard - Here’s a Pattern That Works</h2>
<p>Tables are great until you try to view them on your phone. I have broken more UIs than I can count — until I landed on this reliable pattern.</p>
<h3 id="heading-why-responsive-tables-are-so-frustrating">Why Responsive Tables are so Frustrating</h3>
<p>You want:</p>
<ul>
<li><p>Headers</p>
</li>
<li><p>Rows</p>
</li>
<li><p>Clean alignment</p>
</li>
<li><p>Scrollable on mobile</p>
</li>
<li><p>Sticky headers, maybe?</p>
</li>
</ul>
<p>But what you often get:</p>
<ul>
<li><p>Overflowing cells</p>
</li>
<li><p>Squashed text</p>
</li>
<li><p>Ugly horizontal scroll</p>
</li>
<li><p>Broken layouts</p>
</li>
</ul>
<p><strong>Responsive grids? Easy.</strong><br /><strong>Responsive tables? Still awkward.</strong></p>
<p>And that’s because:</p>
<p>Tables weren’t designed for mobiles — they were designed for data-heavy desktops.</p>
<p>But with the right pattern, you can make it work beautifully for any screen.</p>
<h3 id="heading-the-pattern-that-works-table-inside-a-scrollable-container">The Pattern that works: Table inside a Scrollable Container.</h3>
<p>This is the cleanest, least hacky approach I have used — and it works 99% of the time.</p>
<ol>
<li><strong>Step 1: Wrap your table in a scroll container</strong></li>
</ol>
<pre><code class="lang-css">&lt;<span class="hljs-selector-tag">div</span> <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">table-wrapper</span>"&gt;
  &lt;<span class="hljs-selector-tag">table</span>&gt;
    &lt;<span class="hljs-selector-tag">thead</span>&gt;...&lt;/<span class="hljs-selector-tag">thead</span>&gt;
    &lt;<span class="hljs-selector-tag">tbody</span>&gt;...&lt;/<span class="hljs-selector-tag">tbody</span>&gt;
  &lt;/<span class="hljs-selector-tag">table</span>&gt;
&lt;/<span class="hljs-selector-tag">div</span>&gt;

<span class="hljs-selector-class">.table-wrapper</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">overflow-x</span>: auto;
}

<span class="hljs-selector-tag">table</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">min-width</span>: <span class="hljs-number">600px</span>; <span class="hljs-comment">/* or whatever your data requires */</span>
  <span class="hljs-attribute">border-collapse</span>: collapse;
}
</code></pre>
<p>This creates <strong>horizontal scrolling on small screens</strong>, but keeps things readable and aligned.</p>
<ol start="2">
<li><strong>Step 2: Use Sticky Headers (Optional but Delightful)</strong></li>
</ol>
<pre><code class="lang-css"><span class="hljs-selector-tag">thead</span> <span class="hljs-selector-tag">th</span> {
  <span class="hljs-attribute">position</span>: sticky;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">background</span>: white;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">1</span>;
}
</code></pre>
<p>Now, when users scroll, your headers stay visible.</p>
<p>Bonus: Add a subtle box shadow to the sticky header for depth</p>
<ol start="3">
<li><strong>Step 3: Make it Keyboard — Tough Friendly</strong></li>
</ol>
<pre><code class="lang-css"><span class="hljs-selector-class">.table-wrapper</span> {
  <span class="hljs-attribute">-webkit-overflow-scrolling</span>: touch;
  <span class="hljs-attribute">scrollbar-width</span>: thin;
  <span class="hljs-attribute">scroll-behavior</span>: smooth;
}
</code></pre>
<p>This improves the mobile feel <strong>without janky scrollbars.</strong></p>
<h3 id="heading-responsive-table-enhancements">Responsive Table Enhancements</h3>
<ul>
<li><p>✅ Add <code>white-space: nowrap</code> on key cells to prevent word wrap</p>
</li>
<li><p>✅ Use <code>text-overflow: ellipsis</code> for long content</p>
</li>
<li><p>✅ Add <code>title</code> or tooltips for truncated values</p>
</li>
<li><p>✅ Highlight rows on hover for readability</p>
</li>
<li><p>✅ Use <code>aria-label</code> and <code>scope</code> attributes for accessibility</p>
</li>
</ul>
<h2 id="heading-next-gen-web-animations-15-css-and-javascript-techniques-that-will-make-your-website-300-more-engaging">Next-Gen Web Animations: 15 CSS and JavaScript Techniques That Will Make Your Website 300% More Engaging</h2>
<p>Web animations are experiencing a renaissance. <strong>New CSS features like</strong> <code>@scroll-timeline</code><strong>,</strong> <code>animation-timeline</code><strong>, and the Web Animations API is revolutionizing how we create engaging user experiences.</strong> These modern techniques offer unprecedented control over timing, performance, and accessibility while maintaining smooth 60fps animations.</p>
<p>Studies show that well-crafted animations can increase user engagement by up to 300% and improve perceived value by 25%. But poorly implemented animations can destroy the user experience and tank your Core Web Vitals Score.</p>
<p>In this comprehensive guide, we will explore cutting-edge animation techniques that will transform your website into an engaging, performant experience that users love.</p>
<h3 id="heading-why-modern-animation-techniques-beat-traditional-approaches">Why Modern Animation Techniques Beat Traditional Approaches.</h3>
<p>This foundation section highlights the inefficiencies of traditional JavaScript-based animation methods, which often lead to problems like constant style recalculations, main thread blocking, poor battery life, and accessibility issues.</p>
<p>It then introduces the benefits of modern approaches, primarily GPU acceleration for smooth 60fps performance, better battery life, and built-in accessibility support, setting the stage for the subsequent techniques.</p>
<h3 id="heading-the-problem-with-old-animation-methods">The Problem with Old Animation Methods</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional approach - performance killers</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">animateElement</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> start = <span class="hljs-literal">null</span>;

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">step</span>(<span class="hljs-params">timestamp</span>) </span>{
    <span class="hljs-keyword">if</span> (!start) start = timestamp;
    <span class="hljs-keyword">const</span> progress = timestamp - start;

    element.style.left = <span class="hljs-built_in">Math</span>.min(progress / <span class="hljs-number">10</span>, <span class="hljs-number">200</span>) + <span class="hljs-string">'px'</span>;

    <span class="hljs-keyword">if</span> (progress &lt; <span class="hljs-number">2000</span>) {
      requestAnimationFrame(step);
    }
  }

  requestAnimationFrame(step);
}

<span class="hljs-comment">// Problems:</span>
<span class="hljs-comment">// - Constant style recalculations</span>
<span class="hljs-comment">// - Main thread blocking</span>
<span class="hljs-comment">// - Poor battery life</span>
<span class="hljs-comment">// - Accessibility issues</span>
</code></pre>
<p><strong>The Modern Advantage</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">/* Modern approach - GPU accelerated */</span>
<span class="hljs-meta">@keyframes</span> slideIn {
  <span class="hljs-keyword">from</span> { transform: translateX(<span class="hljs-number">-100</span>%); }
  to { transform: translateX(<span class="hljs-number">0</span>); }
}
.element {
  animation: slideIn <span class="hljs-number">0.3</span>s ease-out;
  will-change: transform;
}
<span class="hljs-comment">/* Benefits:
   - GPU acceleration
   - Smooth 60fps performance  
   - Better battery life
   - Built-in accessibility support
*/</span>
</code></pre>
<p><strong>Performance comparison:</strong></p>
<ul>
<li><p><strong>CPU usage</strong>: 70% reduction</p>
</li>
<li><p><strong>Battery consumption</strong>: 50% improvement</p>
</li>
<li><p><strong>Frame rate consistency</strong>: 95% fewer dropped frames</p>
</li>
<li><p><strong>Accessibility</strong>: Native <code>prefers-reduced-motion</code> support</p>
</li>
</ul>
<h3 id="heading-understanding-modern-animation-primitives">Understanding Modern Animation Primitives</h3>
<p>Refer to <a target="_blank" href="https://medium.com/@orami98/next-gen-web-animations-15-css-javascript-techniques-that-will-make-your-website-300-more-c85a948486ea">this article</a> for more details.</p>
<h2 id="heading-css-tricks">CSS Tricks</h2>
<h3 id="heading-the-one-css-trick-every-front-end-shouldnt-have-learned-years-ago-currentcolor">The One CSS Trick Every Front-end Shouldn’t Have Learned Years Ago: currentColor</h3>
<p>You just spent an hour updating your website’s color scheme. Now you’re hunting through 47 different SVG files, manually changing hex codes from <code>#0088cc</code> to <code>#ff6b6b</code>.</p>
<p>Sound familiar? That sinking feeling in your stomach when you realize you hardcoded colors everywhere?</p>
<p>I’ve been there. Multiple times. Until I discovered <code>currentColor</code>.</p>
<p><strong>The Problem Nobody Talks About</strong></p>
<p>Here’s what happened to me last year: I built a navigation menu with custom icons. Beautiful SVGs, perfectly crafted. Then my client said, “Can we make the icons match the text color on hover?”</p>
<p>Simple request, right?</p>
<p>Wrong.</p>
<p>Each icon had <code>fill="#2c3e50"</code> hardcoded in the SVG. I had to:</p>
<ol>
<li><p>Update the SVG fill color</p>
</li>
<li><p>Update the hover state fill color</p>
</li>
<li><p>Make sure they matched the text color</p>
</li>
<li><p>Repeat for every. Single. Icon.</p>
</li>
</ol>
<p>Three different places. Three chances to mess up. And when they inevitably asked to change the color again? Back to square one.</p>
<p><strong>There had to be a better way.</strong></p>
<p><strong>Enter currentColor: CSS’s Forgotten Superhero</strong></p>
<p><code>currentColor</code> is exactly what it sounds like; it grabs whatever color value is currently set on an element. It's been around since 2010 (older than some of the frameworks you're probably using), but hardly anyone talks about it.</p>
<p>Here’s the simplest example:</p>
<pre><code class="lang-typescript">.card {
  color: red;
  border: <span class="hljs-number">3</span>px solid currentColor;
}
</code></pre>
<p>That border? It’s red. No repetition. No separate variable. It just… inherits.</p>
<p><strong>Before currentColor (the painful way):</strong></p>
<pre><code class="lang-typescript">.button {
  color: #<span class="hljs-number">0088</span>cc;
  border: <span class="hljs-number">2</span>px solid #<span class="hljs-number">0088</span>cc; <span class="hljs-comment">/* Hope you don't typo this */</span>
  box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">2</span>px <span class="hljs-number">4</span>px #<span class="hljs-number">0088</span>cc; <span class="hljs-comment">/* Or this */</span>
}
</code></pre>
<p><strong>After currentColor (the same way):</strong></p>
<pre><code class="lang-typescript">.button {
  color: #<span class="hljs-number">0088</span>cc;
  border: <span class="hljs-number">2</span>px solid currentColor;
  box-shadow: <span class="hljs-number">0</span> <span class="hljs-number">2</span>px <span class="hljs-number">4</span>px currentColor;
}
</code></pre>
<p>Change one value. Everything updates. That’s the scratch for your itch.</p>
<h3 id="heading-propover-api">Propover API</h3>
<p>CSS has the ability to create popovers without needing any JavaScript.</p>
<p>You can now build interactive popups like tooltips, models, or dropdowns using just HTML and CC. This is made possible with the Popover API.</p>
<p>To create a popover, you need two basic elements:</p>
<ul>
<li><p>A <strong>trigger</strong> (like a button)</p>
</li>
<li><p>A <strong>popover element</strong> (like a div)</p>
</li>
</ul>
<p>You use the new <code>popover</code> attribute on the popover element. And you connect the trigger to it using the <code>popover-target</code> attribute.</p>
<pre><code class="lang-typescript">&lt;!-- Trigger Button --&gt;
&lt;button popovertarget=<span class="hljs-string">"myPopover"</span>&gt;Follow Me&lt;/button&gt;

&lt;!-- Popover Element --&gt;
&lt;div id=<span class="hljs-string">"myPopover"</span> popover&gt;
  Thank you <span class="hljs-keyword">for</span> following me!
&lt;/div&gt;
</code></pre>
<ul>
<li><p>When you click the “Subscribe” button, the div with <code>id="myPopover"</code> appears as a popover.</p>
</li>
<li><p>You can close it by pressing <strong>Escape</strong> or <strong>clicking outside</strong>.</p>
</li>
</ul>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*LKTGPyELIW4kxQAUgiWoIA.png" alt="Pop over content" /></p>
<p>At first, the popover just appears and disappears instantly. If you want to add smooth opening and closing animations, <strong>you can combine it with CSS transitions.</strong></p>
<pre><code class="lang-typescript">#myPopover {
  transform: translateY(<span class="hljs-number">-2</span>rem);
  opacity: <span class="hljs-number">0</span>;
  transition: transform <span class="hljs-number">0.3</span>s ease, opacity <span class="hljs-number">0.3</span>s ease;
}

#myPopover:open {
  transform: translateY(<span class="hljs-number">0</span>);
  opacity: <span class="hljs-number">1</span>;
}
</code></pre>
<h3 id="heading-field-sizing-for-inputs-and-textareas">Field-Sizing for Inputs and Textareas</h3>
<p>Another super handy update in CSS is the new <code>field-sizing</code> property.<br />It allows input fields, textareas, and select dropdowns to <strong>automatically resize</strong> based on their content.</p>
<p>Before this, input fields and text areas had a <strong>fixed width and height</strong>.</p>
<p>If the content was too big or too small, the field stayed the same size, unless you manually adjusted it with JavaScript or set a fixed size.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*_Ogki7j3kzSNfSfNoRT8jA.gif" alt /></p>
<p>With <code>field-sizing</code>, the browser can <strong>adjust the size of the field automatically</strong> depending on the text inside.</p>
<p>You simply apply:</p>
<pre><code class="lang-typescript">input, textarea, select {
  field-sizing: content;
}
</code></pre>
<p>Now, when users type something or select an option:</p>
<p>The width (and sometimes the height) will grow or shrink based on the content.</p>
<p>Example:</p>
<pre><code class="lang-typescript">&lt;textarea placeholder=<span class="hljs-string">"Start typing..."</span>&gt;&lt;/textarea&gt;
&lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span> placeholder=<span class="hljs-string">"Your Name"</span>&gt;
&lt;select&gt;
  &lt;option&gt;Short&lt;/option&gt;
  &lt;option&gt;Much longer text option&lt;/option&gt;
&lt;/select&gt;
</code></pre>
<pre><code class="lang-typescript">textarea, input, select {
  field-sizing: content;
  max-width: <span class="hljs-number">100</span>%; <span class="hljs-comment">/* Optional: prevent it from getting too large */</span>
}
</code></pre>
<ul>
<li><p>The textarea will expand as you type more lines.</p>
</li>
<li><p>The input will grow wider if you type a long name.</p>
</li>
<li><p>The select box will resize depending on the selected option.</p>
</li>
</ul>
<p>In short <code>field-sizing</code> helps your form fields grow naturally with the user’s input, creating smarter and more responsive forms with just one line of CSS.</p>
<h3 id="heading-control-elements-height-and-width">Control Element’s Height and Width</h3>
<p>You can use the resize property to allow users to set any element’s width, height, or both manually.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741434267589/a1d0ab76-174e-47bb-9c54-2b8bcaa1d8c1.webp" alt class="image--center mx-auto" /></p>
<p>There are mainly 3 values of resize. They are <code>horizontal</code>, <code>vertical</code> and <code>both</code>.</p>
<p><code>resize: horizontal</code> allows you to drag the element to increase its width.</p>
<p><code>resize: vertical</code> allows you to drag the element to increase its height.</p>
<p><code>resize: both</code> allows you to drag the element to increase both its width and height.</p>
<p>But wait. It does not work for every element.</p>
<p>Those are — inline elements and block elements having the <code>overflow</code> property is set to <code>visible</code> .</p>
<h3 id="heading-centering-without-flexbox-or-grid">Centering without Flexbox or Grid</h3>
<p>Remember the struggle of centering elements with CSS?</p>
<p>You would reach for a flexbox or grid just to center one thing.</p>
<p>Not anymore!</p>
<p>The new align-content property makes entering elements - no extra containers.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.my-element</span> {
  <span class="hljs-attribute">display</span>: block;
  <span class="hljs-attribute">align-content</span>: center;
}
</code></pre>
<p>✅ Supported in Chrome, Edge, and Firefox</p>
<p>❌ Not yet available in Safari</p>
<h3 id="heading-the-masonry-layout-with-just-one-line">The Masonry Layout with just one line</h3>
<p>We all loved the Pinterest-inspired masonry layout, where elements with varying heights stack in a neat, gap-free way. While many developers think you need a JavaScript or external libraries to achieve it, the solution is surprisingly simple:</p>
<p>Use the <code>columns</code> property.</p>
<p>Instead of struggling with Grid or Flexbox (which both leave an awkward gap), you can define columns directly with CSS:</p>
<p><code>columns: 300px;</code></p>
<p>Want to set the max number of columns for responsiveness? Add a second parameter like this:</p>
<p><code>columns: 300px 4;</code></p>
<p>That’s it. The browser automatically adjusts the layout for you. No fuss, no gaps, no headaches.</p>
<h3 id="heading-universal-box-sizing">Universal box sizing</h3>
<p>Probably one of the most forgotten properties to set. It simply defines how the box reacts to the border and the padding of elements within it.</p>
<p>By default, the box-sizing is set to content-box, which means that the width and height of an element only include its padding and border. This can cause unexpected layout problems.</p>
<p>To fix this, you can simply add the following one-liner to your CSS:</p>
<pre><code class="lang-css">*, *<span class="hljs-selector-pseudo">::before</span>, *<span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">box-sizing</span>: border-box;
}
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">200px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">10px</span> solid black;
}
</code></pre>
<ul>
<li><p>With <code>box-sizing: content-box</code> → total width = <strong>200 + 20×2 + 10×2 = 260px</strong></p>
</li>
<li><p>With <code>box-sizing: border-box</code> → total width = <strong>exactly 200px</strong></p>
</li>
</ul>
<h3 id="heading-the-math-gets-an-upgrade">The math gets an upgrade</h3>
<p>CSS has always allowed simple calculations with the <code>calc()</code> function.</p>
<p>However, its capabilities were somewhat limited.</p>
<p>The latest update brings a suite of new math functions, including <code>round()</code>, <code>mod()</code>, and <code>rem()</code>.</p>
<p>The old way: Limited Math with <code>calc()</code>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.element</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">100%</span> - <span class="hljs-number">50px</span>);
}
</code></pre>
<p>The new ways with advanced math functions</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-built_in">round</span>(<span class="hljs-number">2.5px</span>); <span class="hljs-comment">/* Rounds to 3px */</span>
}
<span class="hljs-selector-class">.stripe</span><span class="hljs-selector-pseudo">:nth-child(odd)</span> {
  <span class="hljs-attribute">left</span>: <span class="hljs-built_in">calc</span>(var(--index) * <span class="hljs-number">50px</span> mod <span class="hljs-number">200px</span>);
}
<span class="hljs-selector-class">.circle</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-built_in">rem</span>(<span class="hljs-number">10px</span>, <span class="hljs-number">3px</span>); <span class="hljs-comment">/* Outputs 1px */</span>
}
</code></pre>
<h3 id="heading-forms-with-new-pseudo-classes">Forms with New Pseudo-Classes</h3>
<p>Forms are the backbone of user interaction on the web, but ensuring users input the right data can be very tricky.</p>
<p>While CSS provided some basic pseudo-classes like <code>:valid</code> and <code>:invalid</code> for form validation, they weren’t always intuitive or flexible.</p>
<p>The new <code>:user-valid</code> and <code>:user-invalid</code> pseudo-classes refine this process by focusing on user interaction.</p>
<p>The old way: Static validation with <code>:valid</code> and <code>:invalid</code></p>
<p>Previously, you could validate form fields with <code>:valid</code> and <code>:invalid</code>.</p>
<p>However, these pseudo-classes are triggered as soon as the page is loaded, leading to premature styling changes.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">:valid</span> {
  <span class="hljs-attribute">border-color</span>: green;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">:invalid</span> {
  <span class="hljs-attribute">border-color</span>: red;
}
</code></pre>
<p>The New Way with <code>:user-valid</code> and <code>:user-invalid</code></p>
<p>The <code>:user-valid</code> and <code>:user-invalid</code> pseudo-classes only apply styles <strong>after the user interacts with the field</strong>, avoiding premature validation styles.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">:user-valid</span> {
  <span class="hljs-attribute">border-color</span>: green;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">:user-invalid</span> {
  <span class="hljs-attribute">border-color</span>: red;
}
</code></pre>
<h3 id="heading-animating-sizes-with-the-interpolate-size-property">Animating Sizes with the Interpolate-Size Property</h3>
<p>Animating size changes like <code>height</code>, <code>width</code>, or <code>padding</code> has always been tricky in CSS.</p>
<p>The new <code>interpolate-size</code> property transforms how size animations work.</p>
<p>The old way: Using max-value or JavaScript:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.collapsible</span> {
  <span class="hljs-attribute">overflow</span>: hidden;
  <span class="hljs-attribute">max-height</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">transition</span>: max-height <span class="hljs-number">0.3s</span> ease-out;
}
<span class="hljs-selector-class">.collapsible</span><span class="hljs-selector-class">.open</span> {
  <span class="hljs-attribute">max-height</span>: <span class="hljs-number">500px</span>; <span class="hljs-comment">/* Assumes a fixed maximum height */</span>
}
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> element = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.collapsible'</span>);
element.style.height = <span class="hljs-string">`<span class="hljs-subst">${element.scrollHeight}</span>px`</span>;
</code></pre>
<p>The new way with <code>interpolate-size</code></p>
<pre><code class="lang-css"><span class="hljs-selector-class">.collapsible</span> {
  <span class="hljs-attribute">interpolate-size</span>: height ease-in-out <span class="hljs-number">0.3s</span>;
}
<span class="hljs-selector-class">.collapsible</span><span class="hljs-selector-class">.open</span> {
  <span class="hljs-attribute">height</span>: auto;
}
</code></pre>
<ul>
<li><p>The browser calculates the starting and ending sizes dynamically, even for <code>auto</code> values.</p>
</li>
<li><p>Transitions are seamless, no matter how much content is inside the element.</p>
</li>
</ul>
<h3 id="heading-remove-image-backgrounds-with-one-line-of-css">Remove Image Backgrounds With One Line Of CSS</h3>
<p>There are a few images whose background does not match the website’s background, like the image below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737283005104/3c968812-d527-44f4-a62b-313ee2141d24.webp" alt class="image--center mx-auto" /></p>
<p>The background color of the image is completely different from your expected color.</p>
<p>The most common option you might think is to change your design.</p>
<p>Change the background color to the product’s background color.</p>
<p>Not really…</p>
<p>There is a property in CSS called <code>mix-blend-mode</code> where all the magic happens.</p>
<p>Your image is contained inside an individual <code>div</code> element. Each div has its own background color and each image has its own.</p>
<p>How the <code>mix-blend-mode</code> really work?</p>
<p>When you apply <code>mix-blend-mode</code> for the <code>image</code> element, the browser starts a color comparison between the image and the div element.</p>
<p>Here, the style will be <code>mix-blend-mode: darken</code></p>
<p>The color comparison will be done on a pixel-by-pixel basis. In a certain position, two pixels are compared with each other.</p>
<p>If the <code>mix-blend-mode</code> property is <code>darken</code>, the darker pixel between the two will be kept.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737283502841/dba41ed3-944e-414a-93ec-cf3a0c46c556.webp" alt class="image--center mx-auto" /></p>
<p>Looks like the image’s background has been removed, but actually, it blends with the background.</p>
<h3 id="heading-logical-properties">Logical Properties</h3>
<p>Tired of using <code>margin-left</code>, <code>margin-right</code>, <code>margin-top</code>, and <code>margin-bottom</code>?</p>
<p>Here’s an example that uses logical properties for layout adjustments:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box</span> {
  <span class="hljs-attribute">margin-block</span>: <span class="hljs-number">5px</span> <span class="hljs-number">10px</span>;    <span class="hljs-comment">/* 5px top margin, 10px bottom margin */</span>
  <span class="hljs-attribute">margin-inline</span>: <span class="hljs-number">20px</span> <span class="hljs-number">30px</span>;  <span class="hljs-comment">/* 20px left margin, 30px right margin */</span>
}
</code></pre>
<p>The same method works for <code>padding</code> as well.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box</span> {
  <span class="hljs-attribute">padding-block</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span>; <span class="hljs-comment">/* 10px top/bottom padding, 20px bottom padding */</span>
  <span class="hljs-attribute">padding-inline</span>: <span class="hljs-number">15px</span> <span class="hljs-number">25px</span>; <span class="hljs-comment">/* 15px left padding, 25px right padding */</span>
}
</code></pre>
<p>These properties adjust automatically based on the text direction (e.g., left-to-right or right-to-left), making your code more readable, shorter, flexible, and international-friendly.</p>
<h3 id="heading-empty-element">Empty Element</h3>
<p>No more empty space or unwanted margins from empty elements! This CSS trick automatically hides any elements that have no content. It’s incredibly useful for dynamic content that might not always be present, ensuring your content stays clean and tight.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.element</span><span class="hljs-selector-pseudo">:empty</span> { <span class="hljs-attribute">display</span>: none }
</code></pre>
<p>Consider combining this with pseudo-elements such as <code>::before</code> or <code>::after</code> for placeholders or default states when the element is empty. This can add a nice touch of detail to your design without any clutter.</p>
<h3 id="heading-responsive-styling-based-on-orientation">Responsive Styling based on orientation</h3>
<p>Adjust your site’s background color (or any other style) based on the design orientation with this simple media query. It’s perfect for ensuring your design looks great in both portrait and landscape modes, especially on mobile devices where users might frequently change orientation.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@media</span> (<span class="hljs-attribute">orientation:</span> landscape) {
  <span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#333</span>
  }
}
</code></pre>
<h3 id="heading-dynamic-sibling-influence">Dynamic Sibling Influence</h3>
<p>Create an interactive element on your page without JavaScript! This CSS one-liner changes the style of a target element when you hover over its sibling. It’s great for highlighting related elements or showing hidden information when another element is interacted with.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.sibling</span><span class="hljs-selector-pseudo">:hover</span> ~ <span class="hljs-selector-class">.target</span> { <span class="hljs-attribute">color</span>: <span class="hljs-number">#007bff</span> }
<span class="hljs-selector-class">.sibling</span><span class="hljs-selector-pseudo">:hover</span> + <span class="hljs-selector-class">.target</span> { <span class="hljs-attribute">color</span>: <span class="hljs-number">#007bff</span> }
</code></pre>
<p>The <code>~</code> the selector in CSS targets all subsequent siblings that match the selector, allowing you to style multiple elements that follow other specific elements within the same parent.</p>
<p>On the other hand, the <code>+</code> selector targets only the directly adjacent sibling that immediately follows the specified element, limiting the effect to just one next sibling.</p>
<h3 id="heading-the-target-pseudo-class">The <code>:target</code> Pseudo Class</h3>
<p>CSS offers several pseudo-classes that let you style elements based on different states (<code>:hover</code>, <code>:focus</code>, <code>:checked</code>).</p>
<p>But there’s one you might not have used before — <code>:target</code></p>
<p>The <code>:target</code> pseudo-class applies styles to an element <strong>when its ID matches the Fragment identifier in the URL</strong> (the part after #).</p>
<p>This behavior is commonly seen when clicking on an anchor link that jumps to a section on the same page.</p>
<p>Here’s a simple example:</p>
<pre><code class="lang-typescript">&lt;a href=<span class="hljs-string">"#contact"</span>&gt;Go to Contact&lt;/a&gt;
&lt;section id=<span class="hljs-string">"contact"</span>&gt;
  &lt;p&gt;Welcome to the contact section!&lt;/p&gt;
&lt;/section&gt;
</code></pre>
<p>When clicked, the URL changes to <code>yourwebsite.com/#contact</code>, and the section becomes the <strong>target</strong>. That’s where the power of <code>:target</code> comes in.</p>
<h3 id="heading-vs-in-css3">: vs:: in CSS3</h3>
<p>Have you always used trial and error to style elements when it involves either a colon <code>:</code> or a pair of colon <code>::</code>?</p>
<p>: precedes and identifies the state of an element while <code>::</code> “creates” element(s). The difference between <code>:</code> and <code>::</code> is that the former describes the state of a selected element, usually involving user interaction, while the latter is used to create elements as a part of the selected element and/or used to target elements using the selected element as a reference.</p>
<p>It is important to note that <code>:</code> creates pseudo-classes; some examples are<br /><code>:hover</code> - to style an element when the user is on it, without selecting, i,e hovers over an element<br /><code>:active</code> - to style an element when clicked ie, when an element is active<br /><code>:visited</code> - to style anchor tags (links) when a user has clicked on them.<br /><code>:focus</code> - to style an input field that the user clicked on.</p>
<p>While <code>::</code> creates pseudo-elements. Some examples of pseudo-elements are<br /><code>::before</code> - targets created an element that precedes the selected element<br /><code>::after</code> - targets created an element that succeeds the selected element</p>
<h3 id="heading-conditions">Conditions</h3>
<p>Conditions can be written in several ways, depending on where you want to use them. Selectors are scoped to their elements, while media queries are scoped globally and need their own selectors.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Attribite Selectors */</span>
<span class="hljs-selector-attr">[data-attr=<span class="hljs-string">'true'</span>]</span> {
    <span class="hljs-comment">/* if */</span>
}
<span class="hljs-selector-attr">[data-attr=<span class="hljs-string">'false'</span>]</span> {
    <span class="hljs-comment">/* elseif */</span>
}
<span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-attr">[data-attr]</span>) {
    <span class="hljs-comment">/* else */</span>
}
</code></pre>
<pre><code class="lang-css"><span class="hljs-comment">/* Pseudo Classes */</span>
<span class="hljs-selector-pseudo">:checked</span> {
    <span class="hljs-comment">/* if */</span>
}
<span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-pseudo">:checked)</span> {
    <span class="hljs-comment">/* else */</span>
}
</code></pre>
<pre><code class="lang-css"><span class="hljs-comment">/* Media queries */</span>
<span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-attribute">color</span>: red; <span class="hljs-comment">/* else */</span>
}
<span class="hljs-keyword">@media</span> (min-width &gt; <span class="hljs-number">600px</span>) {
    <span class="hljs-selector-pseudo">:root</span> {
        <span class="hljs-attribute">color</span>: blue; <span class="hljs-comment">/* if */</span>
    }
}
</code></pre>
<h3 id="heading-the-difference-between-width-100-and-width-auto">The Difference Between <code>width: 100%</code> and <code>width: auto</code></h3>
<p>The <code>width</code> property is used to set the width of an element. By default, <code>width</code> sets the width of the content area, but if the <code>box-sizing</code> property is set to <code>border-box</code>, it instead sets the width of the border area.</p>
<pre><code class="lang-typescript">&lt;!DOCTYPE html&gt;
&lt;html lang=<span class="hljs-string">"en"</span>&gt;
  &lt;head&gt;
    &lt;meta charset=<span class="hljs-string">"UTF-8"</span> /&gt;
    &lt;meta name=<span class="hljs-string">"viewport"</span> content=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;
    &lt;title&gt;Document&lt;/title&gt;
    &lt;style&gt;
      div {
        color: #fff;
        font-size: <span class="hljs-number">2</span>rem;
        text-align: center;
      }
      .parent {
        width: <span class="hljs-number">600</span>px;
        height: <span class="hljs-number">600</span>px;
        background-color: #<span class="hljs-number">2177</span>b8;
        border: <span class="hljs-number">10</span>px solid #<span class="hljs-number">21373</span>d;
        padding: <span class="hljs-number">20</span>px;
      }
      .child {
        background-color: #ee3f4d;
        border: <span class="hljs-number">10</span>px solid #d8e3e7;
        margin: <span class="hljs-number">20</span>px;
        height: <span class="hljs-number">100</span>px;
      }
      .auto {
        width: auto;
      }
      .hundred-percent {
        width: <span class="hljs-number">100</span>%;
      }
    &lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"parent"</span>&gt;
      parent
      &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"child auto"</span>&gt;child1: width:auto&lt;/div&gt;
      &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"child hundred-percent"</span>&gt;child2: width:<span class="hljs-number">100</span>%&lt;/div&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>In this example, we set the <code>parent</code> element to have <code>padding: 20px</code> and gave both child elements <code>margin: 20px</code>. <code>child1</code> has a <code>width</code> property of <code>auto</code>, while <code>child2</code> has a <code>width</code> property of <code>100%</code>.</p>
<ul>
<li><code>child1</code> <strong>(width: auto)</strong>: The width adapts to the content area of the parent and does not overflow. <strong>Final width calculation for</strong> <code>child1</code>:</li>
</ul>
<blockquote>
<p><em>Parent width: 600px</em></p>
<p><em>Margin usage: 20px \</em> 2 = 40px*</p>
<p><em>Border usage: 10px \</em> 2 = 20px*</p>
<p><em>Final width = 600px — 40px — 20px =</em> <strong><em>540px</em></strong></p>
</blockquote>
<ul>
<li><code>child2</code> <strong>(width: 100%)</strong>: The width equals the width of the parent and may overflow. <strong>Final width calculation for</strong> <code>child2</code>:</li>
</ul>
<blockquote>
<p><em>Parent width: 600px</em></p>
<p><em>Final width =</em> <strong><em>600px</em></strong> <em>(directly matches the parent width)</em></p>
</blockquote>
<p><strong>Conclusion:</strong></p>
<ul>
<li><p><code>width: 100%</code>: The content area of the child element fills the content area of the parent. If the child element also has <code>padding</code>, <code>border</code>, etc., or if the parent has margins and padding, it may cause the child element to overflow.</p>
</li>
<li><p><code>width: auto</code>: The child element's width is automatically adjusted based on its content, <code>padding</code>, <code>border</code>, and <code>margin</code> to fit within the content area of the parent.</p>
</li>
</ul>
<p>Therefore, in development, it’s advisable to choose <code>width: auto</code>, as it will better maintain the width relative to the parent element. On the other hand, using <code>width: 100%</code> can result in additional spacing being added to the element’s size, potentially leading to layout issues.</p>
<h3 id="heading-pseudo-classes">Pseudo-Classes</h3>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes">Pseudo-classes</a> such as <code>:hover</code>, <code>:focus</code>, and <code>:first-child</code> are options that select HTML elements based on their state rather than their hierarchy or sequence in the document. These selectors allow developers to create more interactive and responsive UIs without using JavaScript.</p>
<p>The following code example demonstrates several pseudo-classes in action:</p>
<pre><code class="lang-css">// <span class="hljs-selector-tag">HTML</span>
...
<span class="hljs-selector-class">.hover-section</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">82</span>, <span class="hljs-number">11</span>, <span class="hljs-number">145</span>); <span class="hljs-comment">/* Changes the background color on hover */</span>
  <span class="hljs-attribute">color</span>: white;
}
<span class="hljs-selector-class">.input-section</span> <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"text"</span>]</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">border-color</span>: orange; <span class="hljs-comment">/* Highlights the input field when focused */</span>
  <span class="hljs-attribute">background-color</span>: lightyellow;
}
<span class="hljs-selector-class">.list-section</span> <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">:first-child</span> {
  <span class="hljs-attribute">color</span>: green; <span class="hljs-comment">/* Styles the first item in a list */</span>
}
<span class="hljs-selector-class">.list-section</span> <span class="hljs-selector-tag">li</span><span class="hljs-selector-pseudo">:last-child</span> {
  <span class="hljs-attribute">color</span>: red; <span class="hljs-comment">/* Styles the last item in a list */</span>
}
</code></pre>
<p>This CSS code example shows how to enhance user interaction by changing styles based on user actions, such as hovering or focusing on elements, and how to style the specific children of a container.</p>
<p>These pseudo-classes are pretty useful when developing forms, navigation menus, or interactive content that requires visual cues to guide user interactions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737286245705/2f33abb7-1db9-4d57-9867-c9f12283a40a.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-minimize-paint-with-will-change">Minimize Paint with <code>will-change</code></h3>
<p><strong><em>Ever hover over a button and the whole thing stutters?</em></strong> That’s because the browser wasn’t ready.</p>
<p>You can hint at upcoming changes:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">will-change</span>: transform, opacity;
}
</code></pre>
<p>This makes the browser prep graphics memory ahead of time.</p>
<blockquote>
<p><em>Translation: smoother animations, no jank.</em></p>
</blockquote>
<p>Don’t overuse it, though, or your browser will hoard memory like it’s toilet paper in 2020.</p>
<h3 id="heading-lazy-load-background-images-with-content-visibility">Lazy-Load Background Images with <code>content-visibility</code></h3>
<p>Why render things the user can’t even see yet? Enter <code>content-visibility</code>:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.card</span> {
  <span class="hljs-attribute">content-visibility</span>: auto;
}
</code></pre>
<p>This delays painting elements until they’re about to scroll into view.</p>
<p><strong>The result?</strong> Faster first paint, lower memory usage.</p>
<p>It’s like telling your browser, <em>“Don’t set the table until the guests actually show up.”</em></p>
<h3 id="heading-prefer-transforms-over-positioning">Prefer Transforms Over Positioning</h3>
<p>Want buttery-smooth animations? Stop animating <code>top</code>, <code>left</code>, <code>width</code>, and <code>height</code>.</p>
<p>They force layout recalculations. Instead, animate <code>transform</code> and <code>opacity</code>.</p>
<p>Example:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box</span> {
  <span class="hljs-attribute">transition</span>: transform <span class="hljs-number">0.3s</span> ease, opacity <span class="hljs-number">0.3s</span> ease;
}

<span class="hljs-selector-class">.box</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateY</span>(-<span class="hljs-number">5px</span>);
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.9</span>;
}
</code></pre>
<p>The GPU handles this like a champ. The CPU can go to sleep.</p>
<h3 id="heading-use-prefers-reduced-motion">Use <code>prefers-reduced-motion</code></h3>
<p>You love fancy animations. Some people don’t. Respect that by adding this:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-reduced-motion:</span> reduce) {
  * {
    <span class="hljs-attribute">animation</span>: none <span class="hljs-meta">!important</span>;
    <span class="hljs-attribute">transition</span>: none <span class="hljs-meta">!important</span>;
  }
}
</code></pre>
<p>This won’t just make your site accessible — it also reduces unnecessary paint cycles for users who opt out.</p>
<p>Accessibility and performance high-five.</p>
<h3 id="heading-skeleton-screens-beat-spinners">Skeleton Screens Beat Spinners</h3>
<p><strong>You know what screams “slow website”? A spinner.</strong></p>
<p>You know what feels fast? A skeleton screen.</p>
<p>Style your placeholders with CSS to mimic the layout:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.skeleton</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(<span class="hljs-number">90deg</span>, #eee <span class="hljs-number">25%</span>, #ddd <span class="hljs-number">50%</span>, #eee <span class="hljs-number">75%</span>);
  <span class="hljs-attribute">background-size</span>: <span class="hljs-number">200%</span> <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">animation</span>: shimmer <span class="hljs-number">1.5s</span> infinite;
}

<span class="hljs-keyword">@keyframes</span> shimmer {
  0% { <span class="hljs-attribute">background-position</span>: -<span class="hljs-number">200%</span> <span class="hljs-number">0</span>; }
  100% { <span class="hljs-attribute">background-position</span>: <span class="hljs-number">200%</span> <span class="hljs-number">0</span>; }
}
</code></pre>
<p>Instead of waiting for content, users feel like it’s <em>loading in</em>. Big difference.</p>
<h3 id="heading-stop-overusing-classes-use-these-css-attribute-selectors-instead">Stop Overusing Classes — Use These CSS Attribute Selectors Instead</h3>
<p>We’ve all seen it:</p>
<pre><code class="lang-typescript">&lt;button <span class="hljs-keyword">class</span>=<span class="hljs-string">"btn btn-primary btn-small active special-action"</span>&gt;Click Me&lt;/button&gt;
</code></pre>
<p>Every time we want to style something slightly different, we slap on another class. Before long, your HTML becomes a tangled mess of utility and semantic noise.</p>
<p>But here’s the thing:</p>
<blockquote>
<p><em>You don’t need a class for everything.</em></p>
</blockquote>
<p>With <strong>CSS attribute selectors</strong>, you can target elements based on their HTML attributes — like <code>type</code>, <code>data-*</code>, <code>href</code>, or even <code>aria-*</code>—without bloating your markup.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762514353004/55fc2ae9-2c7f-44c5-9bc9-e37892518002.webp" alt class="image--center mx-auto" /></p>
<ol>
<li><strong>Targeting Buttons by</strong> <code>type</code></li>
</ol>
<pre><code class="lang-typescript">button[<span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>] {
  background-color: #<span class="hljs-number">10</span>b981;
  color: white;
}
</code></pre>
<p>✅ No need to add <code>.btn-submit</code> everywhere.</p>
<ol start="2">
<li><strong>Styling External Links</strong></li>
</ol>
<pre><code class="lang-typescript">a[href^=<span class="hljs-string">"http"</span>] {
  color: #<span class="hljs-number">3</span>b82f6;
  padding-right: <span class="hljs-number">1.2</span>em;
  background: url(<span class="hljs-string">'external-icon.svg'</span>) no-repeat right center;
  background-size: <span class="hljs-number">1</span>em;
}
</code></pre>
<p>✅ Easily mark external links without class clutter.</p>
<ol start="3">
<li><strong>File Upload Field Style</strong></li>
</ol>
<pre><code class="lang-typescript">input[<span class="hljs-keyword">type</span>=<span class="hljs-string">"file"</span>] {
  border: <span class="hljs-number">2</span>px dashed #<span class="hljs-number">9</span>ca3af;
  padding: <span class="hljs-number">1</span>rem;
  background: #f9fafb;
}
</code></pre>
<p>🎯 Great for clean form styling with no extra markup.</p>
<ol start="4">
<li><strong>ARIA-Based Styling</strong></li>
</ol>
<pre><code class="lang-typescript">[aria-expanded=<span class="hljs-string">"true"</span>] {
  background-color: #d1fae5;
}
</code></pre>
<p>✅ Style accordions, modals, or menus based on state — <strong>no JS class toggles required</strong>.</p>
<ol start="5">
<li><strong>Data Attribute Styling</strong></li>
</ol>
<pre><code class="lang-typescript">[data-theme=<span class="hljs-string">"dark"</span>] {
  background-color: #<span class="hljs-number">1</span>f2937;
  color: white;
}
</code></pre>
<p>🎯 Great for feature toggles, themes, or A/B testing.</p>
<ol start="6">
<li><strong>State Toggles with</strong> <code>[checked]</code> or <code>[disabled]</code></li>
</ol>
<pre><code class="lang-typescript">input[<span class="hljs-keyword">type</span>=<span class="hljs-string">"checkbox"</span>]:checked + label {
  font-weight: bold;
}

button[disabled] {
  opacity: <span class="hljs-number">0.5</span>;
  cursor: not-allowed;
}
</code></pre>
<p>✅ Combine with pseudo-classes for interactive UI.</p>
<ol start="7">
<li><strong>Starts With or Ends With Matching</strong></li>
</ol>
<pre><code class="lang-typescript">a[href$=<span class="hljs-string">".pdf"</span>] {
  color: #dc2626;
  font-weight: bold;
}

img[src^=<span class="hljs-string">"https://cdn."</span>] {
  border-radius: <span class="hljs-number">0.5</span>rem;
}
</code></pre>
<p>📦 Useful for dynamically generated content.</p>
<h2 id="heading-stop-janky-scrolling-the-css-fix-everyone-needs-in-2025">Stop Janky Scrolling: The CSS Fix Everyone Needs in 2025</h2>
<p>They are leaving because your scroll feels broken.</p>
<p>That tiny stutter. That awkward pause when content loads. A lag on mobile when the page is fighting the user’s fingers.</p>
<p>It is death by a thousand scrolls.</p>
<p>And here is the truth: you can fix it with a single CSS property that most developers still overlook in 2025.</p>
<p>Let us break the problem down, fix it step by step, and benchmark the difference together.</p>
<h3 id="heading-why-junky-scroll-kills-conversions">Why Junky Scroll Kills Conversions?</h3>
<p>Scrolling is the heartbeat of the web. If it is not smooth, everything feels cheap.</p>
<ul>
<li><p>A production landing page feels clunky</p>
</li>
<li><p>An article feels heavy</p>
</li>
<li><p>A store feels untrustworthy</p>
</li>
</ul>
<p>You already know how much you care about page speed. Smooth scroll is the speed you can feel.</p>
<p>Most developers unknowingly write CSS that causes the browser to repaint and reflow far more than necessary.</p>
<p>Think of it like this:</p>
<pre><code class="lang-typescript">+----------+      +----------+
|  Scroll  | --&gt;  |  Recalc  |
+----------+      +----------+
                       |
                       v
                  +----------+
                  | Repaint  |
                  +----------+
</code></pre>
<p>Every unnecessary reflow makes the scroll stutter.</p>
<h3 id="heading-the-fix-scroll-behavior-smooth-with-gpu-backed-transforms">The Fix: <code>scroll-behavior: smooth;</code> With GPU-Backed Transforms</h3>
<p>The magic starts simply.</p>
<pre><code class="lang-typescript">html {
  scroll-behavior: smooth;
}

.section {
  transform: translateZ(<span class="hljs-number">0</span>); <span class="hljs-comment">/* force GPU layer */</span>
  will-change: transform;
}
</code></pre>
<ul>
<li><p><code>scroll-behavior: smooth;</code> tells the browser to animate scrolling natively.</p>
</li>
<li><p><code>transform: translateZ(0);</code> forces an element into its own GPU layer.</p>
</li>
<li><p><code>will-change: transform;</code> signals the browser to optimize ahead of time.</p>
</li>
</ul>
<p>Together, these make scrolling <em>butter-smooth</em>, even on weaker devices.</p>
<h3 id="heading-benchmark-before-vs-after">Benchmark: Before vs After</h3>
<p>Let us test a long page with 100 image cards.</p>
<p><strong>Before</strong></p>
<ul>
<li><p>Average scroll FPS: 38</p>
</li>
<li><p>Input delay: noticeable on mobile</p>
</li>
<li><p>Repaint count: 1,246</p>
</li>
</ul>
<p><strong>After CSS Fix</strong></p>
<ul>
<li><p>Average scroll FPS: 58–60</p>
</li>
<li><p>Input delay: nearly invisible</p>
</li>
<li><p>Repaint count: 312</p>
</li>
</ul>
<p><strong>Result:</strong> Over 3x fewer repaints, near 60 FPS scroll.</p>
<h3 id="heading-going-beyond-scroll-snap-type-for-native-feeling"><strong>Going Beyond:</strong> <code>scroll-snap-type</code> for Native Feeling</h3>
<p>Want a scroll that feels like a native app carousel?</p>
<pre><code class="lang-typescript">.container {
  scroll-snap-<span class="hljs-keyword">type</span>: x mandatory;
  overflow-x: auto;
  display: flex;
}

.card {
  scroll-snap-align: start;
  flex: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">300</span>px;
}
</code></pre>
<p>Now your horizontal lists snap naturally. No JavaScript sliders. No jitter.</p>
<h3 id="heading-the-mental-model">The Mental Model</h3>
<p>Think of scroll performance as a pipeline:</p>
<pre><code class="lang-typescript">User Input --&gt; Compositor Thread --&gt; GPU --&gt; Screen
</code></pre>
<p>Your goal is to keep layout and paint out of this loop.</p>
<ul>
<li><p>Use <code>transform</code> and <code>opacity</code> for animations.</p>
</li>
<li><p>Avoid forcing the main thread to reflow during scroll.</p>
</li>
<li><p>Always declare <code>will-change</code> for interactive elements.</p>
</li>
</ul>
<h2 id="heading-how-to-use-css-dev-tools-like-a-senior-developer">How To Use CSS Dev Tools Like a Senior Developer</h2>
<p>Most developers treat CSS Dev Tools like a glorified toggle switch.</p>
<p>They poke around the Styles panel, disable a few rules, maybe slap on <code>padding: 20px</code> and call it “<em>debugging.</em>”</p>
<p>That’s not senior-level work; that is a whack-a-mole with CSS.</p>
<p>If you want to stop wasting hours wondering “why the hell is my margin not working?“ and actually debug CSS like a senior dev, it’s time to unlock the real power of CSS DevTools.</p>
<p>And no, I’m not talking about the basics you already know.</p>
<p>I’m talking about the panels, emulations, and tricks that make CSS stop feeling like black magic.</p>
<p>Let’s dig in.</p>
<ol>
<li><strong>The Style Panel isn’t Just For Toggling</strong></li>
</ol>
<p>Yes, the <strong>Styles panel</strong> is where you check rules. But here’s what seniors actually do with it:</p>
<p><strong>Emulate states</strong></p>
<p>Ever tried debugging a <code>:hover</code> style while… also needing your mouse on DevTools?</p>
<p><em>Painful.</em> Instead, force states (<code>:hover</code>, <code>:active</code>, <code>:focus</code>) from the DevTools sidebar.</p>
<p><strong>Play with classes</strong></p>
<p>Use the “.cls” icon to add/remove classes on the fly without editing your HTML.</p>
<p>Want to see how <code>.is-active</code> breaks your layout? Toggle it. Done.</p>
<p><strong>Write temporary CSS</strong></p>
<p>Hit the little “+” button and drop in experimental styles.</p>
<p>It’s like a sandbox stylesheet that doesn’t touch your actual code.</p>
<p><strong>👉 Action step:</strong> Next time you’re chasing down a hover bug, force the state in DevTools.</p>
<p>Stop playing Twister with your mouse.</p>
<ol start="2">
<li><strong>Computed Panel: The Truth Serum</strong></li>
</ol>
<p>CSS is full of lies.</p>
<p>You <em>think</em> an element has <code>margin: 20px</code> but then, oh look, it’s being overwritten by something else.</p>
<p>The <strong>Computed tab</strong> shows the final, <em>actual</em> styles being applied.</p>
<p>It also visualizes the box model so you can see margin, border, padding, and content at a glance.</p>
<ul>
<li><p><strong>Crossed-out rules?</strong> They’re overridden. Stop blaming CSS when the cascade is doing exactly what you told it to.</p>
</li>
<li><p><strong>Need to find the origin of a property?</strong> Click the property in the computed panel — it jumps straight to the rule that’s winning.</p>
</li>
</ul>
<p><strong>👉 Action step:</strong> Whenever CSS “isn’t working,” check Computed.</p>
<p>It’s the lie detector test your code needs.</p>
<ol start="3">
<li><strong>Layout Tab: The Grid/Flex Lifesaver</strong></li>
</ol>
<p>CSS is full of lies.</p>
<p>You <em>think</em> an element has <code>margin: 20px</code> but then, oh look, it’s being overwritten by something else.</p>
<p>The <strong>Computed tab</strong> shows the final, <em>actual</em> styles being applied.</p>
<p>It also visualizes the box model so you can see margin, border, padding, and content at a glance.</p>
<ul>
<li><p><strong>Crossed-out rules?</strong> They’re overridden. Stop blaming CSS when the cascade is doing exactly what you told it to.</p>
</li>
<li><p><strong>Need to find the origin of a property?</strong> Click the property in the computed panel — it jumps straight to the rule that’s winning.</p>
</li>
</ul>
<p><strong>👉 Action step:</strong> Whenever CSS “isn’t working,” check Computed.</p>
<p>It’s the lie detector test your code needs.</p>
<ol start="4">
<li><strong>Rendering Panel: The Senior Developer’s Playground</strong></li>
</ol>
<p>Buried in the command menu (<code>Ctrl+Shift+P → Rendering</code>), this tab is criminally underused.</p>
<p><strong>Here’s what it gives you</strong></p>
<ul>
<li><p><strong>Color scheme emulation.</strong> Test light/dark mode without changing your OS.</p>
</li>
<li><p><strong>Reduced motion preference.</strong> See how your site behaves for users who disable animations.</p>
</li>
<li><p><strong>Paint flashing.</strong> Highlights what’s repainting on every frame — great for performance debugging.</p>
</li>
<li><p><strong>Layout shift visualization.</strong> See why Google is punishing your site for Cumulative Layout Shift (CLS).</p>
</li>
<li><p><strong>Color blindness simulation.</strong> Stop shipping inaccessible UIs because “the button looked fine to me.”</p>
</li>
</ul>
<p><strong>👉 Action step:</strong> Before launch, run through Rendering with reduced motion and color blindness toggled.</p>
<p>If your app becomes unusable, you’ve got work to do.</p>
<ol start="5">
<li><strong>Animation Panel: Stop Guessing Timing Functions</strong></li>
</ol>
<p><strong>CSS animations can be… slippery.</strong> That bounce you coded? Doesn’t actually look like a bounce.</p>
<p>The <strong>Animations panel</strong> lets you:</p>
<ul>
<li><p>Scrub through animations frame by frame.</p>
</li>
<li><p>Play them at 10% speed to spot glitches.</p>
</li>
<li><p>Adjust duration and easing live.</p>
</li>
<li><p>Copy the adjusted values back into your stylesheet.</p>
</li>
</ul>
<p><strong>👉 Action step:</strong> Open Animations and scrub your next animation.</p>
<p>If it looks clunky and slowed down, your users are noticing too.</p>
<ol start="6">
<li><strong>CSS Overview: The Bird’s-Eye View You Didn’t Know You Needed</strong></li>
</ol>
<p>This one feels like cheating. The <strong>CSS Overview tab</strong> (still “experimental”) takes a full snapshot of your page’s CSS.</p>
<p>It shows you</p>
<ul>
<li><p><strong>Every color in use —</strong> great for catching “why do we have seven slightly different greens?”</p>
</li>
<li><p><strong>Contrast issues —</strong> click to jump to the exact element failing accessibility.</p>
</li>
<li><p><strong>Fonts and weights —</strong> spotting that one rogue Arial when everything else is Inter.</p>
</li>
<li><p><strong>Unused declarations —</strong> rules that literally do nothing.</p>
</li>
<li><p><strong>Media queries —</strong> so you can consolidate breakpoints instead of scattering them like confetti.</p>
</li>
</ul>
<p><strong>👉 Action step:</strong> Run CSS Overview on your project right now.</p>
<p>I guarantee you’ll find at least one color or font inconsistency you didn’t notice.</p>
<ol start="7">
<li><strong>Bonus for Font Debugging (Firefox Only)</strong></li>
</ol>
<p>Ever deployed a site and heard: <em>“The fonts don’t load for me”</em>?</p>
<p>You swear they work fine on your machine.</p>
<blockquote>
<p>Spoiler: it’s because you had the font installed locally.</p>
</blockquote>
<p>In Firefox, set <code>layout.css.font-visibility</code> to <code>1</code> in <code>about:config</code>.</p>
<p>This blocks locally installed fonts so you can catch missing imports before shipping.</p>
<p><strong>👉 Action step:</strong> Test your next project in Firefox with this setting.</p>
<p>If your fancy custom font disappears, congrats — you just saved yourself an embarrassing bug report.</p>
<ol start="8">
<li><strong>Copy CSS Path</strong></li>
</ol>
<p><strong>The time-saver:</strong> Need to target an element with CSS but can’t figure out the selector?</p>
<p>Right-click any element in DevTools → Copy → Copy selector.</p>
<p>It gives you the exact CSS selector to target that element:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/* Instead of guessing: */</span>
.header .nav ul li:nth-child(<span class="hljs-number">3</span>) a

<span class="hljs-comment">/* DevTools gives you: */</span>
#header &gt; nav.main-nav &gt; ul.nav-list &gt; li:nth-child(<span class="hljs-number">3</span>) &gt; a.nav-link
</code></pre>
<p><strong>Bonus:</strong> Use “Copy JS path” for querySelector in JavaScript.</p>
<ol start="9">
<li><strong>CSS Coverage Analysis</strong></li>
</ol>
<p><strong>The performance killer:</strong> Dead CSS bloating your stylesheets.</p>
<p><strong>The solution:</strong> Coverage tab (More tools → Coverage)</p>
<ol>
<li><p>Start recording</p>
</li>
<li><p>Navigate your site</p>
</li>
<li><p>Stop recording</p>
</li>
<li><p>See exactly which CSS rules are used vs unused</p>
</li>
</ol>
<p><strong>Red bars = unused CSS</strong><br /><strong>Green bars = used CSS</strong></p>
<p>I found one client had <strong>73% unused CSS</strong>. That’s a massive performance hit that nobody noticed.</p>
<ol start="10">
<li><strong>Color Picker Superpowers</strong></li>
</ol>
<p><strong>Most people just click the color square and pick colors.</strong></p>
<p><strong>But there’s more:</strong></p>
<ul>
<li><p><strong>Eyedropper tool:</strong> Sample any color from anywhere on the page</p>
</li>
<li><p><strong>Contrast ratio checker:</strong> Ensures accessibility compliance</p>
</li>
<li><p><strong>Color format switcher:</strong> Toggle between hex, rgb, hsl with Shift+Click</p>
</li>
<li><p><strong>Color palette:</strong> DevTools remembers your recent colors</p>
</li>
</ul>
<pre><code class="lang-typescript">.text {
    color: #<span class="hljs-number">007</span>bff; <span class="hljs-comment">/* Shift+click to cycle through formats */</span>
    <span class="hljs-comment">/* #007bff → rgb(0, 123, 255) → hsl(211, 100%, 50%) */</span>
}
</code></pre>
<ol start="11">
<li><strong>CSS Changes Tracker</strong></li>
</ol>
<p><strong>The workflow optimizer:</strong></p>
<p>When you make changes in DevTools, they disappear on refresh. But there’s a hidden tracker:</p>
<ol>
<li><p>Sources tab → Overrides</p>
</li>
<li><p>Enable local overrides</p>
</li>
<li><p>Select a folder to save changes</p>
</li>
<li><p>Now your DevTools changes persist!</p>
</li>
</ol>
<p><strong>Even better:</strong> Sources tab → Changes shows you a diff of everything you modified.</p>
<ol start="12">
<li><strong>Performance Insights for CSS</strong></li>
</ol>
<p><strong>The advanced move:</strong></p>
<p>Performance tab → Start recording → Interact with your page → Stop</p>
<p>Look for:</p>
<ul>
<li><p><strong>Style recalculations</strong> (purple bars)</p>
</li>
<li><p><strong>Layout thrashing</strong> (green bars)</p>
</li>
<li><p><strong>Paint operations</strong> (green bars)</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">/* This triggers expensive reflows: */</span>
.animation {
    animation: slideDown <span class="hljs-number">0.3</span>s ease;
}

<span class="hljs-meta">@keyframes</span> slideDown {
    <span class="hljs-keyword">from</span> { height: <span class="hljs-number">0</span>; }
    to { height: <span class="hljs-number">200</span>px; }
}

<span class="hljs-comment">/* This is much more performant: */</span>
.animation {
    animation: slideDown <span class="hljs-number">0.3</span>s ease;
}

<span class="hljs-meta">@keyframes</span> slideDown {
    <span class="hljs-keyword">from</span> { transform: translateY(<span class="hljs-number">-100</span>%); }
    to { transform: translateY(<span class="hljs-number">0</span>); }
}
</code></pre>
<p>Transform and opacity changes are cheaper than layout properties.</p>
<h2 id="heading-the-css-property-thats-making-every-website-feel-slow">The CSS property that’s making every website feel slow</h2>
<p>Last week, I was debugging why our company’s dashboard felt sluggish on mobile devices. Everything looked perfect in Chrome DevTools on my local machine, but real users were complaining about janky scrolling and laggy interactions. After hours of profiling, I found the culprit hiding in plain sight: box-shadow.</p>
<p>That innocent little property we all love for adding depth and polish was silently murdering our performance.</p>
<h3 id="heading-the-shadow-that-haunts-performance">The Shadow That Haunts Performance</h3>
<p>Box-shadow is one of the most performance-heavy CSS properties you can use. When applied to many components with large blur radius values, it can significantly slow down your webpage. Yet it’s everywhere - cards, buttons, dropdowns. We sprinkle it on like digital seasoning without thinking twice.</p>
<p>Here’s what I discovered: a video streaming interface with blurred backgrounds showed dramatic differences in GPU utilization solely attributed to blur effect implementation. The internal computations required for the blur effect heavily utilize the GPU, and when you multiply that over dozens of elements, you get a choppy user experience.</p>
<h3 id="heading-why-box-shadow-murders-your-frame-rates">Why Box-Shadow murders your frame rates</h3>
<p>Think about what happens when a browser renders the box-shadow:</p>
<pre><code class="lang-typescript">Element <span class="hljs-keyword">with</span> box-shadow renders like <span class="hljs-built_in">this</span>:
┌─────────────────┐
│   Your Element  │ ← Original element
└─────────────────┘
    ▼ ▼ ▼ ▼ ▼     ← Shadow calculation
  ░░░░░░░░░░░░░░░   ← Blur processing
 ░░░░░░░░░░░░░░░░░  ← Color blending
░░░░░░░░░░░░░░░░░░░ ← Composite layers
</code></pre>
<p>The browser has to:</p>
<ol>
<li><p>Create a copy of your element’s silhouette</p>
</li>
<li><p>Offset it based on your x/y values</p>
</li>
<li><p>Apply blur calculations (this is the killer)</p>
</li>
<li><p>Composite it behind your element</p>
</li>
<li><p>Repeat for every frame during animations</p>
</li>
</ol>
<p>When used on a large number of elements or a large blur radius, it can significantly slow down your page. I have seen sites with 50+ elements using <code>box-shadow: 0 10px 25px rgba(0,0,0,0.15)</code> wondering why their Lighthouse performance score is in the red.</p>
<p>Let’s check out the real-world impact and these alternative solutions in <a target="_blank" href="https://medium.com/@sohail_saifi/the-css-property-thats-making-every-website-feel-slow-c860d0599715">this article</a>.</p>
<h2 id="heading-top-10-css-mistakes-even-experienced-devs-still-make">Top 10 CSS Mistakes Even Experienced Devs Still Make</h2>
<p><mark>If you’ve ever spent 45 minutes adjusting a </mark> <code>margin</code> <mark>only to realize it was a </mark> <code>padding</code> <mark>issue all along, you’re not alone.</mark> CSS is deceptively simple. And even seasoned frontend engineers make the same silent missteps that later haunt QA reports, mobile views, and weird browser edge cases.</p>
<p>Here are 10 CSS mistakes that even experienced developers keep making…yes, <em>even the ones who tweet confidently about CSS Grid</em>.</p>
<h3 id="heading-1-using-z-index-without-understanding-stacking-context"><strong>1. Using</strong> <code>z-index</code> Without Understanding Stacking Context</h3>
<p>Cranking up <code>z-index: 9999</code> should solve it, right?<br />Not if you’ve unknowingly created a new stacking context.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754737866225/8ddcbe6c-be8d-4099-b207-d33a075574a6.webp" alt class="image--center mx-auto" /></p>
<p>Any <code>transform</code>, <code>opacity &lt; 1</code>, <code>filter</code>, <code>will-change</code>, or <code>position: fixed</code> inside an element can create a new stacking context, which isolates <code>z-index</code> levels from the outside world. This one causes endless ghost-layer bugs, especially in modals or dropdowns.</p>
<h3 id="heading-2-misusing-vh-units-on-mobile"><strong>2. Misusing</strong> <code>vh</code> Units on Mobile</h3>
<p>Setting an element to <code>height: 100vh</code> used to be the go-to for fullscreen sections. <strong>But on mobile? It breaks.</strong></p>
<p>iOS Safari subtracts the browser UI height differently. So what looks fine on a desktop often cuts off or overflows awkwardly on phones.</p>
<p><strong>Fix:</strong> Use <code>100dvh</code> (dynamic viewport height) or JS to set height dynamically if full-viewport fidelity is critical.</p>
<h3 id="heading-3-forgetting-that-flex-children-dont-shrink-by-default">3. Forgetting That Flex Children Don’t Shrink by Default</h3>
<p>Ever have a card layout break because one element is way too wide? That’s usually because <code>flex-shrink</code> isn’t behaving as expected.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754737926332/6af67ae4-0df9-4df0-aebf-ce624d482ad8.webp" alt class="image--center mx-auto" /></p>
<p>When elements have content that doesn’t wrap or images without max-widths, the container explodes. A quick <code>min-width: 0</code> or <code>overflow: hidden</code> can sometimes fix the unexpected growth.</p>
<h3 id="heading-4-using-position-absolute-inside-a-flexbox-without-a-relative-parent"><strong>4. Using</strong> <code>position: absolute</code> Inside a Flexbox Without a <code>relative</code> Parent</h3>
<p>This is a silent killer. If you absolutely position something inside a flex container but forget to set <code>position: relative</code> on the flex parent, your <code>top/right/bottom/left</code> values don’t do what you think they do.</p>
<p>It works sometimes because of inherited flow…and fails just enough to make you question your skills.</p>
<h3 id="heading-5-over-nesting-when-its-not-needed">5. Over-Nesting When It’s Not Needed</h3>
<p>We’ve all done this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754737991032/63662db4-6fba-417f-87cd-6bd2329fa458.webp" alt class="image--center mx-auto" /></p>
<p>Why? Just use <code>.card-title</code>.</p>
<p>Excessive nesting makes CSS harder to override, understand, and maintain. Especially when using BEM or CSS modules, keep selectors shallow and intentional.</p>
<h3 id="heading-6-relying-on-important-as-a-first-resort"><strong>6. Relying on</strong> <code>!important</code> as a First Resort</h3>
<p>The <code>!important</code> tag is a crutch. Once you use it, you start a spiral where other styles need <code>!important</code> just to win.</p>
<blockquote>
<p><em>If your CSS is fighting itself, chances are the problem isn’t specificity, it’s architecture. Audit your cascade.</em></p>
<p>Use <code>!important</code> only when you absolutely <em>must</em> override a third-party style and cannot change the source.</p>
</blockquote>
<h3 id="heading-7-forgetting-about-box-sizing-border-box">7. Forgetting About <code>box-sizing: border-box</code></h3>
<p>Still using <code>width: 100%</code> + <code>padding</code> and wondering why things overflow?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754738042125/ade407b8-5a47-439b-8817-9099f3ba235a.webp" alt class="image--center mx-auto" /></p>
<p>This tiny rule ensures that <strong>paddings are included <em>inside</em> the defined width/height, not added <em>after</em> it.</strong> Saves layouts. Every time.</p>
<h3 id="heading-8-missing-the-power-of-logical-properties">8. Missing the Power of Logical Properties</h3>
<p>Still writing <code>margin-left</code> and <code>padding-top</code>? That works, but it breaks in right-to-left (RTL) layouts or vertical writing modes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754738078412/8de6c77f-ae3b-4a95-8b54-3564619863d9.webp" alt class="image--center mx-auto" /></p>
<p><strong>Logical properties</strong> make your <strong>layout direction-agnostic</strong> and future-proof.</p>
<h3 id="heading-9-overusing-display-flex-when-you-needed-block"><strong>9. Overusing</strong> <code>display: flex</code> When You Needed <code>block</code></h3>
<p>Sometimes, all you need is <code>display: block</code> and <code>margin: auto</code> to center something. But we’re so used to typing <code>display: flex; align-items: center; justify-content: center</code> that we forget the simpler tools.</p>
<p>Over-flexing often leads to layout bugs where child elements don’t behave like you expect.</p>
<h3 id="heading-10-letting-your-css-snowball">10. Letting Your CSS Snowball</h3>
<p><mark>The biggest </mark> <strong><mark>mistake</mark></strong><mark>? </mark> <strong><mark>Thinking CSS doesn’t need structure</mark></strong><mark>.</mark></p>
<p>If you’re not using a convention (BEM, SMACSS, Tailwind, CSS Modules, whatever), your styles will grow into a tangled mess.</p>
<blockquote>
<p><strong>CSS is global by default.</strong> That’s its power and its curse.</p>
<p>Without discipline, every new feature becomes an accidental override.</p>
<p>CSS might not throw runtime errors, but it can absolutely wreck your product quietly and visually.</p>
</blockquote>
<p>Even senior devs mess this up. The goal isn’t to avoid mistakes entirely; <strong><em>it’s to recognize the traps, name them, and debug faster next time</em></strong>.</p>
<h1 id="heading-tailwind-css">Tailwind CSS</h1>
<p>Exploring the rise of the utility-first CSS framework that’s changed the game. Here’s how Tailwind became so popular and why I have refused to use any other CSS solution since the year 2022.</p>
<h2 id="heading-best-practices-for-tailwind-css">Best Practices for Tailwind CSS</h2>
<h3 id="heading-do-not-repeat-the-same-class-names-for-elements">Do not repeat the same class names for elements</h3>
<p>Prefer to create separate components with uniform styles throughout the application instead of writing the same class names in multiple places or creating a new class name including all the Tailwind class names using <code>@apply</code> directive.</p>
<p>Doing so would offer us the flexibility of updating our styles with minimal effort, as we have to update the class names in only a single place.</p>
<p>Suppose we have a <code>h1</code> tag that will be used in multiple places. We have two approaches to achieve it:</p>
<ol>
<li><p>We can create a component <code>H1Heading</code> with Tailwind classes applied to it and reuse this component whenever it is required.</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">const</span> H1Heading = <span class="hljs-function">(<span class="hljs-params">{ children }</span>) =&gt;</span> {
   <span class="hljs-keyword">return</span> (
     &lt;h1 className=<span class="hljs-string">"text-2xl md:text-4xl lg:text-5xl xl:text-6xl font-bold text-black"</span>&gt;
       {children}
     &lt;/h1&gt;
   );
 };
</code></pre>
</li>
<li><p>We can create a class in our CSS file that includes all the tailwind class names for the particular element and use the class name wherever required.</p>
<pre><code class="lang-css"> <span class="hljs-keyword">@tailwind</span> base;
 <span class="hljs-keyword">@tailwind</span> components;
 <span class="hljs-keyword">@tailwind</span> utilities;

 <span class="hljs-selector-class">.heading-1</span> {
     @apply text-2xl <span class="hljs-attribute">md</span>:text-<span class="hljs-number">4</span>xl lg:text-<span class="hljs-number">5</span>xl xl:text-<span class="hljs-number">6</span>xl font-bold text-black
 }
</code></pre>
<pre><code class="lang-xml"> <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"heading-1"</span>&gt;</span>
   Some random heading
 <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>
</code></pre>
</li>
</ol>
<h3 id="heading-maintain-an-organized-style-guide-using-design-tokens">Maintain an organized style guide using design tokens</h3>
<p>Design tokens are a way to store and manage your design variables, such as color palettes, spacing scale, typography scale, or breakpoints. With design tokens, you can create consistent and reusable styles that are easy to update and maintain.</p>
<p>You can create the design tokens in the <code>tailwind.config.js</code> file. This is a good way to centralize your design tokens and make them available to all of your Tailwind CSS classes.</p>
<p>Suppose our application follows a particular design system. We can add these guidelines to our Tailwind configuration:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> defaultTheme <span class="hljs-keyword">from</span> <span class="hljs-string">"tailwindcss/defaultTheme"</span>;

<span class="hljs-keyword">const</span> config = {
  content: [
    <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx,mdx}"</span>,
  ],
  theme: {
    extend: {
      fontFamily: {
        manrope: <span class="hljs-string">"var(--font-manrope)"</span>,
      },
      colors: {
        ...defaultTheme.colors,
        theme: <span class="hljs-string">"#7743DB"</span>,
        light: {
          primary: <span class="hljs-string">"#FFFFFF"</span>,
          secondary: <span class="hljs-string">"#f1f1ef"</span>,
        },
        dark: {
          primary: <span class="hljs-string">"#0F0F0F"</span>,
          secondary: <span class="hljs-string">"#202020"</span>,
        },
        <span class="hljs-string">"background"</span>: <span class="hljs-string">"#F5F5F5"</span>,
      },
      screens: {
        ...defaultTheme.screens,
        xs: <span class="hljs-string">"340px"</span>,
        sm: <span class="hljs-string">"420px"</span>,
      },
      spacing: {
        spacing: {
          ...defaultTheme.spacing,
          <span class="hljs-number">1</span>: <span class="hljs-string">'5px'</span>,
          <span class="hljs-number">2</span>: <span class="hljs-string">'10px'</span>,
          <span class="hljs-number">3</span>: <span class="hljs-string">'15px'</span>,
          <span class="hljs-number">4</span>: <span class="hljs-string">'20px'</span>,
          <span class="hljs-number">5</span>: <span class="hljs-string">'25px'</span>
        }
      }
    },
  },
};
</code></pre>
<h3 id="heading-avoid-using-arbitrary-values">Avoid using arbitrary values</h3>
<p>Imagine our web application follows some color scheme where we have <code>#7743DB</code> as our theme color and <code>#0D0D0D</code> as our background color.</p>
<p>We can add these colors to our Tailwind configuration and refer to them using class names, such as <code>bg-background</code> <code>text-theme</code> instead of using arbitrary values at multiple places, i.e. <code>bg-[#0D0D0D]</code> or <code>text-[#7743DB]</code>.</p>
<p>Now, if we want to change our application’s color scheme, we just need to update our tailwind configuration instead of renaming the arbitrary class names in multiple places.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> defaultTheme <span class="hljs-keyword">from</span> <span class="hljs-string">"tailwindcss/defaultTheme"</span>;

<span class="hljs-keyword">const</span> config = {
  content: [
    <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx,mdx}"</span>,
  ],
  theme: {
    extend: {
      colors: {
        ...defaultTheme.colors,
        theme: <span class="hljs-string">"#7743DB"</span>,
        background: <span class="hljs-string">"#0D0D0D"</span>
      },
    },
  },
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> config;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> ColoredText = <span class="hljs-function">(<span class="hljs-params">{ children }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
     &lt;span className=<span class="hljs-string">"text-theme"</span>&gt;
          {children}
     &lt;/span&gt;
  );
};
</code></pre>
<h3 id="heading-avoid-applying-dynamically-generated-class-names">Avoid applying dynamically generated class names</h3>
<p>You might have encountered this issue while working with dynamic classes: Whenever we apply dynamic class names based on a state or condition, the class name appears in the browser's elements panel, but its corresponding CSS does not.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> BorderBox = <span class="hljs-function">(<span class="hljs-params">{ borderColor }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    &lt;div className={<span class="hljs-string">`border border-solid border-[<span class="hljs-subst">${borderColor}</span>]`</span>}&gt;
      Some Random Text
    &lt;/div&gt;
  );
};
</code></pre>
<p>This is because Tailwind scans your source code for classes using regular expressions to extract every string that could possibly be a class name. Hence, any broken class name string such as <code>border-[${borderColor}]</code> would not be recognized by Tailwind at build time, and it would not be included in the output CSS file of Tailwind.</p>
<p>Suppose we have to change the border color of our element based on the color code passed in props. There are two ways to it:</p>
<ol>
<li><p>Defining a separate class name for each state value. This is only applicable if you know all the expected values of <code>borderColor</code> at build time.</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">const</span> BorderBox = <span class="hljs-function">(<span class="hljs-params">{ borderColor }</span>) =&gt;</span> {
   <span class="hljs-keyword">return</span> (
     &lt;div
       className={clsx(<span class="hljs-string">"border border-solid"</span>, {
         <span class="hljs-string">"border-black"</span>: borderColor === <span class="hljs-string">"black"</span>,
         <span class="hljs-string">"border-red-500"</span>: borderColor === <span class="hljs-string">"red"</span>,
         <span class="hljs-string">"border-green-500"</span>: borderColor === <span class="hljs-string">"green"</span>,
       })}
     &gt;
       Some Random Text
     &lt;/div&gt;
   );
 };
 <span class="hljs-comment">// Note: clsx is utility package for constructing className strings conditionally.</span>
</code></pre>
</li>
<li><p>If we do not know all the expected values of borderColor at the build time, it is better to pass the border color in the style attribute of the element to support unknown values.</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">const</span> BorderBox = <span class="hljs-function">(<span class="hljs-params">{ borderColor }</span>) =&gt;</span> {
   <span class="hljs-keyword">return</span> (
     &lt;div className=<span class="hljs-string">"border border-solid"</span> style={{ borderColor }}&gt;
       Some Random Text
     &lt;/div&gt;
   );
 };
</code></pre>
</li>
</ol>
<h3 id="heading-the-game-changing-content-configuration-hack">The Game-Changing Content Configuration Hack</h3>
<p>While everyone obsesses over purging unused CSS (which, yes, is important), there is a more subtle performance killer hiding in plain sight: poorly configured content paths.</p>
<p>Most developers do this:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// tailwind.config.js - The WRONG way</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  content: [
    <span class="hljs-string">"./src/**/*.{js,jsx,ts,tsx,html}"</span>,
    <span class="hljs-string">"./public/**/*.html"</span>,
    <span class="hljs-string">"./components/**/*.{js,jsx}"</span>,
  ],
  <span class="hljs-comment">// ... rest of config</span>
}
</code></pre>
<p>Looks innocent, right? <strong>Wrong.</strong></p>
<p>This overly broad configuration forces Tailwind to scan thousands of unnecessary files, creating massive build time and bloated CSS output. Your development server crawls, your production build takes forever, and your final CSS bundle includes styles you will never use.</p>
<p>Here’s the hack that changed everything for me:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// tailwind.config.js - The OPTIMIZED way</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  content: [
    <span class="hljs-comment">// Be surgical about your paths</span>
    <span class="hljs-string">"./src/components/**/*.{jsx,tsx}"</span>,
    <span class="hljs-string">"./src/pages/**/*.{jsx,tsx}"</span>,
    <span class="hljs-string">"./src/app/**/*.{jsx,tsx}"</span>,

    <span class="hljs-comment">// Exclude heavy directories</span>
    <span class="hljs-string">"!./src/assets/**"</span>,
    <span class="hljs-string">"!./src/utils/**"</span>,
    <span class="hljs-string">"!./node_modules/**"</span>,

    <span class="hljs-comment">// Include only files that actually use Tailwind</span>
    {
      files: [<span class="hljs-string">"./src/**/*.{js,jsx,ts,tsx}"</span>],
      transform: <span class="hljs-function">(<span class="hljs-params">content</span>) =&gt;</span> content.match(<span class="hljs-regexp">/class[Name]*\s*[:=]\s*["`']([^"`']*)["`']/g</span>) || []
    }
  ],
  <span class="hljs-comment">// Enable JIT mode for instant compilation</span>
  mode: <span class="hljs-string">'jit'</span>,
  <span class="hljs-comment">// ... rest of config</span>
}
</code></pre>
<p><strong>The magic happens in three ways:</strong></p>
<ol>
<li><p><strong>Surgical Path Targeting</strong>: Instead of scanning everything, we target only files that actually contain Tailwind classes</p>
</li>
<li><p><strong>Smart Exclusions</strong>: We explicitly exclude heavy directories that don’t need scanning.</p>
</li>
<li><p><strong>Content Transformation</strong>: We use a custom transform to extract only relevant class patterns.</p>
</li>
</ol>
<p>After implementing this hack in a React e-commerce project:</p>
<ul>
<li><p><strong>Build time</strong>: 45 seconds → 12 seconds (73% faster)</p>
</li>
<li><p><strong>Development server startup</strong>: 8 seconds → 2.5 seconds</p>
</li>
<li><p><strong>Final CSS bundle</strong>: 145KB → 23KB (84% smaller)</p>
</li>
<li><p><strong>Lighthouse Performance Score</strong>: 67 → 94</p>
</li>
</ul>
<p>My client was speedless. The same website that used to take 8 seconds now loads in under 2 seconds.</p>
<h3 id="heading-creating-a-utility-to-read-tailwind-configuration-in-javascript">Creating a utility to read Tailwind Configuration in JavaScript</h3>
<p>In web applications, a situation rarely arises where you need to read some CSS design token value in JavaScript, but when it does, we generally hardcode the CSS design token value in our code while working with Tailwind. This is not a good practice, as in the future, if you change your design token value in your Tailwind configuration, your code might still refer to the old value, which can cause unwanted behavior.</p>
<p>Hence, we can build a custom utility function to read the Tailwind configuration in our code.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> resolveConfig <span class="hljs-keyword">from</span> <span class="hljs-string">"tailwindcss/resolveConfig"</span>;
<span class="hljs-keyword">import</span> tailwindConfig <span class="hljs-keyword">from</span> <span class="hljs-string">"../tailwind.config"</span>;

<span class="hljs-keyword">const</span> getTailwindConfiguration = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> resolveConfig(tailwindConfig).theme;
};

<span class="hljs-keyword">const</span> config = getTailwindConfiguration();

<span class="hljs-built_in">console</span>.log(config.colors.red[<span class="hljs-number">500</span>]); <span class="hljs-comment">// would print #ef4444</span>
</code></pre>
<h3 id="heading-defining-tailwind-plugins-to-register-newcomplex-css-styles">Defining Tailwind Plugins to register new/complex CSS styles</h3>
<p>Tailwind provides us with plugins to register new styles and inject them into the user’s stylesheet using JavaScript instead of writing custom CSS styling in stylesheets.</p>
<p>I prefer this approach, as writing custom CSS classes means essentially rewriting CSS and sacrificing Tailwind’s organized workflow and simple maintenance.</p>
<p>Suppose we want to create a <code>.btn</code> class that has several styles attached to it. This is how we can achieve it:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> plugin <span class="hljs-keyword">from</span> <span class="hljs-string">"tailwindcss/plugin"</span>;

<span class="hljs-keyword">const</span> config = {
  content: [
    <span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx,mdx}"</span>,
  ],
  plugins: [
    plugin(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">{ addComponents }</span>) </span>{
      addComponents({
        <span class="hljs-string">".btn"</span>: {
          padding: <span class="hljs-string">".5rem 1rem"</span>,
          borderRadius: <span class="hljs-string">".25rem"</span>,
          fontWeight: <span class="hljs-string">"600"</span>,
        },
      });
    }),
  ],
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> config;
</code></pre>
<p>This is how the <code>.btn</code> class would look like when you hover over it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739967322956/bee78412-8c37-4d54-951b-5b6af8d972bb.webp" alt class="image--center mx-auto" /></p>
<p>Tailwind supports registering complex styles as well, along with user-provided values. You can go through the Tailwind official documentation for <a target="_blank" href="https://tailwindcss.com/docs/plugins#overview">the plugin</a> to know more about it.</p>
<h2 id="heading-tailwind-css-tips-amp-tricks">Tailwind CSS Tips &amp; Tricks</h2>
<ol>
<li><strong>Styling children from the parent element (`&amp;_*`)</strong></li>
</ol>
<p>Generally, you can just put utility classes on any element to style it. But, there is a case when you don’t have control over certain elements, like when you are using external components.</p>
<p>In that case, you can use this class to style elements inside those components. There are 2 ways to style elements inside their parent:</p>
<ul>
<li><p>Using <code>*:{utility-class}</code> to style direct children, which is <a target="_blank" href="https://tailwindcss.com/docs/hover-focus-and-other-states#styling-direct-children">documented here</a>.</p>
</li>
<li><p>Using <code>[&amp;_{children-selector}]:{utility-class}</code> to style any descendant of the parent element. I don’t know why, but this way is not documented in the official documentation.</p>
</li>
</ul>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">'[&amp;&gt;p]:font-bold *:uppercase [&amp;_.link-class]:text-teal-500'</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        This text is styled by{' '}
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">'link-class'</span> <span class="hljs-attr">href</span>=<span class="hljs-string">'#'</span>&gt;</span>
            its ancestor
        <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">div</span>&gt;</span>
</code></pre>
<p>The underscore in the code is a replacement for a space. You can also use <code>id</code> or <code>class</code> selectors.</p>
<ol start="2">
<li><strong>Let the DOM state style itself (data/aria,</strong> <code>peer</code>, and <code>group</code>)</li>
</ol>
<p>Skip JS for visual states you already have in the DOM.</p>
<p>Toggle <code>data-*</code> or <code>aria-*</code> attributes and let Tailwind variants do the heavy lifting.</p>
<p><strong>Tabs with</strong> <code>data-state</code><strong>:</strong></p>
<pre><code class="lang-typescript">&lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"flex gap-2"</span> role=<span class="hljs-string">"tablist"</span>&gt;
  &lt;button data-state=<span class="hljs-string">"active"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"px-3 py-1 rounded-brand data-[state=active]:bg-brand data-[state=active]:text-white"</span>&gt;Overview&lt;/button&gt;
  &lt;button <span class="hljs-keyword">class</span>=<span class="hljs-string">"px-3 py-1 rounded-brand data-[state=active]:bg-brand data-[state=active]:text-white"</span>&gt;Settings&lt;/button&gt;
&lt;/div&gt;
</code></pre>
<p><strong>Disclosure with</strong> <code>aria-expanded</code> <strong>+</strong> <code>peer</code><strong>:</strong></p>
<pre><code class="lang-css">&lt;<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">aria-expanded</span>="<span class="hljs-selector-tag">false</span>" <span class="hljs-selector-tag">id</span>="<span class="hljs-selector-tag">acc-1</span>" <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">peer</span> <span class="hljs-selector-tag">px-3</span> <span class="hljs-selector-tag">py-2</span> <span class="hljs-selector-tag">rounded-brand</span> <span class="hljs-selector-tag">border</span>"&gt;
  <span class="hljs-selector-tag">FAQ</span>
&lt;/<span class="hljs-selector-tag">button</span>&gt;
&lt;<span class="hljs-selector-tag">div</span> <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">max-h-0</span> <span class="hljs-selector-tag">overflow-hidden</span> <span class="hljs-selector-tag">peer-</span><span class="hljs-selector-attr">[aria-expanded=true]</span><span class="hljs-selector-pseudo">:max-h-96</span> <span class="hljs-selector-tag">transition-</span><span class="hljs-selector-attr">[max-height]</span>"&gt;
  &lt;<span class="hljs-selector-tag">p</span>&gt;<span class="hljs-selector-tag">Answer</span> <span class="hljs-selector-tag">goes</span> <span class="hljs-selector-tag">here</span>.&lt;/<span class="hljs-selector-tag">p</span>&gt;
&lt;/<span class="hljs-selector-tag">div</span>&gt;
</code></pre>
<p><strong>Nested hover/focus with</strong> <code>group</code><strong>:</strong></p>
<pre><code class="lang-css">&lt;<span class="hljs-selector-tag">a</span> <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">group</span> <span class="hljs-selector-tag">block</span> <span class="hljs-selector-tag">p-4</span> <span class="hljs-selector-tag">rounded-brand</span> <span class="hljs-selector-tag">border</span>"&gt;
  &lt;<span class="hljs-selector-tag">span</span> <span class="hljs-selector-tag">class</span>="<span class="hljs-selector-tag">underline</span> <span class="hljs-selector-tag">group-hover</span><span class="hljs-selector-pseudo">:no-underline"</span>&gt;<span class="hljs-selector-tag">Read</span> <span class="hljs-selector-tag">more</span>&lt;/<span class="hljs-selector-tag">span</span>&gt;
&lt;/<span class="hljs-selector-tag">a</span>&gt;
</code></pre>
<p><strong>👉Reality:</strong> If you need complex timelines or animations, sure — write JS.</p>
<p>But for 80% of UI toggles, the semantics are already in the markup. Use them.</p>
<ol start="3">
<li><strong>Style based on sibling state</strong> <code>peer-*</code></li>
</ol>
<p>You can use <code>peer-{state}:{utility-class}</code> to style an element based on its sibling state.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">class</span>=<span class="hljs-string">'max-w-sm mx-auto'</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">'block'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">'block text-sm font-medium text-slate-700'</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <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">class</span>=<span class="hljs-string">'peer rounded p-3 w-full outline-none border border-solid border-slate-300'</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Type an invalid email to see error message'</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">'mt-2 invisible peer-invalid:visible text-pink-600 text-sm'</span>&gt;</span>Please provide a valid email address.<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">form</span>&gt;</span>
</code></pre>
<p>In the demo above, you can see that the error message is only visible when the input element (sibling) has <code>invalid</code> state.</p>
<ol start="4">
<li><strong>Style based on descendant</strong> <code>has-*</code></li>
</ol>
<p>There is also a way to style an element based on its children or descendants. The example use case for this is when looping a post list that the post item can contain an image or not.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740054583935/6800d54c-0487-453c-9ec0-593da42886f9.png" alt class="image--center mx-auto" /></p>
<p>In real use cases, you probably use JavaScript logic instead using <code>has-[{element-selector}]</code> to style based on the descendant element. But, <code>has-*</code> also supports for descendant state.</p>
<p>In the demo above, you can see that I used <code>has-[img:hover]</code> to changed the background when the image hovered. You can use another state like <code>invalid</code>, <code>disabled</code>, <code>focus</code>, etc. This is the best case where you can use <code>has-*</code> selector.</p>
<p>You can also combine <code>has-*</code> with another modifier like <code>peer-has-*</code>.</p>
<ol start="5">
<li><strong>Custom Classes with Arbitrary Values</strong></li>
</ol>
<p>Custom classes with Arbitrary Classes are like writing CSS directly inside the class. It looks something like <code>text-[#09836d]</code> or <code>mr-[75px]</code>. You can use a class with arbitrary as the last resort when you can’t find any predefined utility class that fulfills your use case.</p>
<p>You can pass any value that is valid, such as the CSS property class, to a custom class. You can even pass Tailwind CSS variables. You can find more examples of Arbitrary values in the <a target="_blank" href="https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values">official documentation</a>.</p>
<p>One thing that usually becomes an issue when using classes with arbitrary values is when you need to pass a value with a space. For example, when you want to pass <code>box-shadow</code> value <code>0 0 2px 0 #abcdef</code>. In this case, you can replace the space with <code>_</code>, so the class will be <code>shadow-[0_0_2px_0_#abcdef]</code>.</p>
<p>Keep in mind that a CSS class can’t contain whitespace.</p>
<ol start="6">
<li><strong>Color Opacity</strong></li>
</ol>
<p>Did you know that you can apply opacity to your color classes? It works in classes that contain color value like <code>bg-{color}</code>, <code>text-{color}</code>, <code>border-{color}</code>. You just need to add <code>/{opacity-value}</code> after the class. The opacity value is 0 to 100 with an interval of 5.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740055591674/9b348185-9c32-44af-97dc-fe3e3f7f82bd.png" alt class="image--center mx-auto" /></p>
<ol start="7">
<li><strong>Customize / Disable Tailwind container class</strong></li>
</ol>
<p>Tailwind CSS comes with a built-in responsive container class. The container will adjust in <code>xs</code>, <code>sm</code>, <code>md</code>, and <code>lg</code> breakpoints. By default, the container class has no padding and center positioning. But if you want to customize it, you can add container configurations in <code>tailwind.config.js</code> file.</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">/** @type {import('tailwindcss').Config} */</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
 ...,
  theme: {
    container: {
      center: <span class="hljs-literal">true</span>,
      padding: <span class="hljs-string">'1rem'</span>
 },
 },
}
</code></pre>
<p>You can also disable or remove the container class by setting <code>container: false</code> in <code>corePlugins</code> configuration.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/** @type {import('tailwindcss').Config} */</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
 ...,
  corePlugins: {
    container: <span class="hljs-literal">false</span>
 },
}
</code></pre>
<ol start="8">
<li><strong>Space between elements (</strong><code>space-*</code> <strong>and</strong> <code>gap-*</code><strong>)</strong></li>
</ol>
<p>When displaying a list or grid, we usually need spacing between list or grid items. We often use <code>padding-{top/bottom/left/right}</code> or <code>margin-{top/bottom/left/right}</code> and end up with excess spacing in the last item.</p>
<p>You can solve this by using <code>space-*</code> or <code>gap-*</code> in the list or grid container. <code>space</code> works for all element displays (<code>block</code>, <code>flex</code>, <code>grid</code>, etc), while <code>gap-*</code> only works for <code>flex</code> and <code>grid</code> element.</p>
<p>If you use <code>space-*</code>, you have to define the direction, whether vertical or horizontal spacing. Use <code>space-x-*</code> for horizontal space and <code>space-y-*</code> for vertical spacing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740217902915/6b7b01ba-5462-4f52-a4c0-6c35db5963b4.png" alt class="image--center mx-auto" /></p>
<ol start="9">
<li><strong>Replace Js</strong> <code>substring()</code> <strong>with</strong> <code>truncate</code> <strong>and</strong> <code>line-clamp-*</code></li>
</ol>
<p>Before I knew <code>truncate</code> and <code>line-clamp-*</code>, I usually used the JavaScript function <code>substring(0, n)</code> to truncate a string. However, the sentences often have inconsistent widths because each letter has a different width.</p>
<p><code>truncate</code> and <code>line-clamp-*</code> solve this, because they don’t care about the number of letters; they only care about the number of lines.</p>
<p>You can use <code>truncate</code> to truncate sentences into 1 line. If you want to truncate a paragraph after, let’s say 3 lines, you can use <code>line-clamp-3</code>.</p>
<pre><code class="lang-typescript">&lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">'max-w-xs mx-auto bg-slate-100 rounded p-3 mb-3'</span>&gt;
    &lt;p <span class="hljs-keyword">class</span>=<span class="hljs-string">'truncate'</span>&gt;
        This is text <span class="hljs-keyword">with</span> <span class="hljs-string">`truncate`</span>: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur
        adipiscing elit.
    &lt;/p&gt;
&lt;/div&gt;
&lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">'max-w-xs mx-auto bg-slate-100 rounded p-3'</span>&gt;
    &lt;p <span class="hljs-keyword">class</span>=<span class="hljs-string">'line-clamp-2'</span>&gt;
        This is text <span class="hljs-keyword">with</span> <span class="hljs-string">`line-clamp-2`</span>: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur
        adipiscing elit.
    &lt;/p&gt;
&lt;/div&gt;
</code></pre>
<ol start="10">
<li><code>backdrop-blur-*</code> <strong>– The Frosted Glass Effect You Forgot</strong></li>
</ol>
<p>Everyone loves a good glassmorphism effect — until they forget how easy Tailwind makes it.</p>
<pre><code class="lang-typescript">&lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"backdrop-blur-sm bg-white/30"</span>&gt;
  &lt;p <span class="hljs-keyword">class</span>=<span class="hljs-string">"text-white"</span>&gt;Frosty content&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<p>Instantly adds depth and modernity.</p>
<p>And no, you don’t need five layers of CSS anymore.</p>
<ol start="11">
<li><code>scroll-mt-*</code> <strong>– Scroll-To Sections Done Right</strong></li>
</ol>
<p>Ever anchor to a section only to find your fixed header hiding it?</p>
<p><code>scroll-mt-*</code> to the rescue:</p>
<pre><code class="lang-typescript">&lt;h2 id=<span class="hljs-string">"features"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"scroll-mt-16"</span>&gt;Features&lt;/h2&gt;
</code></pre>
<p>Now, your content actually shows below the header.</p>
<blockquote>
<p>UX magic, powered by one tiny utility.</p>
</blockquote>
<ol start="12">
<li><code>prose</code> <strong>(Typography plugin) – Markdown Never Looked So Good</strong></li>
</ol>
<p>Stop styling every <code>&lt;p&gt;</code> manually.</p>
<p>Wrap your Markdown content in a <code>prose</code> container:</p>
<pre><code class="lang-typescript">&lt;article <span class="hljs-keyword">class</span>=<span class="hljs-string">"prose lg:prose-xl"</span>&gt;
  &lt;!-- Markdown content here --&gt;
&lt;/article&gt;
</code></pre>
<p>Clean, beautiful typography out of the box.</p>
<p>Your blog posts, docs, and release notes will thank you.</p>
<ol start="13">
<li><code>isolate</code> <strong>and</strong> <code>isolation-auto</code> <strong>– Z-Index Nightmares? Solved.</strong></li>
</ol>
<p>Ever get stuck fighting z-index wars? Adding <code>isolate</code> to your container creates a new stacking context, keeping your modal, dropdown, or tooltip sane.</p>
<pre><code class="lang-typescript">&lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"relative isolate"</span>&gt;
  &lt;!-- Stacking context safe zone --&gt;
&lt;/div&gt;
</code></pre>
<blockquote>
<p>No more random overlaps. Just clean, predictable layering.</p>
</blockquote>
<ol start="14">
<li><strong>Use</strong> <code>@layer components</code> <strong>+</strong> <code>@apply</code> <strong>to codify patterns (not micro-utilities)</strong></li>
</ol>
<p><code>@apply</code> is not a religion. It’s a screwdriver.</p>
<p>Use it to standardize repeatable “atoms” like buttons, inputs, and cards—so you stop micromanaging 14 classes every time.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* components.css */</span>
<span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;

<span class="hljs-keyword">@layer</span> components {
  <span class="hljs-selector-class">.btn</span> { @apply inline-flex items-center justify-center font-medium rounded-brand shadow-sm transition; }
  <span class="hljs-selector-class">.btn-primary</span> { @apply btn bg-brand/100 text-white <span class="hljs-attribute">hover</span>:bg-brand/<span class="hljs-number">90</span> active:bg-brand/<span class="hljs-number">80</span>; }
  <span class="hljs-selector-class">.btn-ghost</span> { @apply btn bg-transparent text-fg <span class="hljs-attribute">hover</span>:bg-fg/<span class="hljs-number">5</span>; }
  <span class="hljs-selector-class">.field</span> { @apply w-full rounded-brand border border-fg/20 bg-white/90 px-3 py-2 shadow-sm <span class="hljs-attribute">focus</span>:outline-none focus:ring-<span class="hljs-number">2</span> focus:ring-brand/<span class="hljs-number">40</span>; }
  <span class="hljs-selector-class">.card</span> { @apply rounded-brand border border-fg/10 bg-white/70 p-4 shadow; }
}
</code></pre>
<p>Now your HTML stays readable:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn-primary"</span>&gt;</span>Publish<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"field"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Email"</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><strong>👉Reality:</strong> Don’t wrap every single utility in a class.</p>
<p>The goal is to capture patterns, not hide Tailwind. If a style is used once, keep the utilities inline.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://dev.to/madza/18-github-repositories-to-become-a-css-master-lab">https://dev.to/madza/18-github-repositories-to-become-a-css-master-lab</a></p>
<p><a target="_blank" href="https://defensivecss.dev/">https://defensivecss.dev/</a></p>
<p><a target="_blank" href="https://moderncss.dev/12-modern-css-one-line-upgrades/?ref=dailydev">https://moderncss.dev/12-modern-css-one-line-upgrades/?ref=dailydev</a></p>
<p><a target="_blank" href="https://dev.to/poetryofcode/5-hidden-css-properties-you-didnt-know-existed-12h8">https://dev.to/poetryofcode/5-hidden-css-properties-you-didnt-know-existed-12h8</a></p>
<p><a target="_blank" href="https://dev.to/alvaromontoro/css-one-liners-to-improve-almost-every-project-18m?ref=dailydev">https://dev.to/alvaromontoro/css-one-liners-to-improve-almost-every-project-18m?ref=dailydev</a></p>
<p><a target="_blank" href="https://medium.com/design-bootcamp/7-new-css-features-you-dont-know-about-226dd2921cb4">https://medium.com/design-bootcamp/7-new-css-features-you-dont-know-about-226dd2921cb4</a></p>
<p><a target="_blank" href="https://medium.com/design-bootcamp/remove-image-backgrounds-with-one-line-of-css-181581eb05fc">https://medium.com/design-bootcamp/remove-image-backgrounds-with-one-line-of-css-181581eb05fc</a></p>
<p><a target="_blank" href="https://medium.com/syncfusion/5-modern-css-styles-you-should-know-in-2024-3c2bc3ec6093">https://medium.com/syncfusion/5-modern-css-styles-you-should-know-in-2024-3c2bc3ec6093</a></p>
<p><a target="_blank" href="https://blog.stackademic.com/the-top-6-css-cheatsheets-that-will-save-you-hours-2e1d29ed5c24">https://blog.stackademic.com/the-top-6-css-cheatsheets-that-will-save-you-hours-2e1d29ed5c24</a></p>
<p><a target="_blank" href="https://matemarschalko.medium.com/20-css-one-liners-every-css-expert-needs-to-know-bef568ddc265">https://matemarschalko.medium.com/20-css-one-liners-every-css-expert-needs-to-know-bef568ddc265</a></p>
<p><a target="_blank" href="https://medium.com/@karstenbiedermann/goodbye-sass-welcome-back-native-css-b3beb096d2b4">https://medium.com/@karstenbiedermann/goodbye-sass-welcome-back-native-css-b3beb096d2b4</a></p>
<p><a target="_blank" href="https://kaderbiral26.medium.com/15-useful-css-properties-you-should-know-about-d924343d6f9c">https://kaderbiral26.medium.com/15-useful-css-properties-you-should-know-about-d924343d6f9c</a></p>
<p><a target="_blank" href="https://dev.to/stephikebudu/-vs-in-css3-13le?ref=dailydev">https://dev.to/stephikebudu/-vs-in-css3-13le?ref=dailydev</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/why-tailwind-css-became-so-popular-a-developers-guide-11213c08fa46">https://medium.com/better-programming/why-tailwind-css-became-so-popular-a-developers-guide-11213c08fa46</a></p>
<p><a target="_blank" href="https://medium.com/coding-at-dawn/why-tailwind-css-is-48-better-for-performance-than-css-in-js-93c3f9fd59b1">https://medium.com/coding-at-dawn/why-tailwind-css-is-48-better-for-performance-than-css-in-js-93c3f9fd59b1</a></p>
<p><a target="_blank" href="https://medium.com/@imanshurathore/best-practises-for-tailwind-css-in-react-ae2f5e083980">https://medium.com/@imanshurathore/best-practises-for-tailwind-css-in-react-ae2f5e083980</a></p>
<p><a target="_blank" href="https://devaradise.com/tailwind-css-tips-tricks/">https://devaradise.com/tailwind-css-tips-tricks/</a></p>
<p><a target="_blank" href="https://pradipkaity.medium.com/css-only-click-handlers-you-might-not-be-using-but-you-should-69b6c9a07bf2">https://pradipkaity.medium.com/css-only-click-handlers-you-might-not-be-using-but-you-should-69b6c9a07bf2</a></p>
<p><a target="_blank" href="https://medium.com/developers-corner/these-css-pro-tips-and-tricks-will-blow-your-mind-8b58a4a682e5">https://medium.com/developers-corner/these-css-pro-tips-and-tricks-will-blow-your-mind-8b58a4a682e5</a></p>
<p><a target="_blank" href="https://medium.com/@karstenbiedermann/css-and-vibe-coding-why-good-frontend-devs-still-matter-in-the-age-of-ai-09797a7f1287">https://medium.com/@karstenbiedermann/css-and-vibe-coding-why-good-frontend-devs-still-matter-in-the-age-of-ai-09797a7f1287</a></p>
<p><a target="_blank" href="https://medium.com/@karstenbiedermann/the-10-best-new-css-features-in-2025-already-supported-in-all-major-browsers-c4a4cbbf71ea">https://medium.com/@karstenbiedermann/the-10-best-new-css-features-in-2025-already-supported-in-all-major-browsers-c4a4cbbf71ea</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/exploring-the-difference-between-width-100-and-width-auto-81a89c6b6f52">https://javascript.plainenglish.io/exploring-the-difference-between-width-100-and-width-auto-81a89c6b6f52</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/stop-overthinking-media-queries-just-use-these-3-breakpoints-f4abb99329aa">https://javascript.plainenglish.io/stop-overthinking-media-queries-just-use-these-3-breakpoints-f4abb99329aa</a></p>
<p><a target="_blank" href="https://medium.com/design-bootcamp/5-css-features-you-may-not-heard-of-but-super-useful-6eec0912779b">https://medium.com/design-bootcamp/5-css-features-you-may-not-heard-of-but-super-useful-6eec0912779b</a></p>
<p><a target="_blank" href="https://railsdesigner.com/modern-css-overview/?ref=dailydev">https://railsdesigner.com/modern-css-overview/?ref=dailydev</a></p>
<p><a target="_blank" href="https://cody-by-umar.medium.com/responsive-tables-are-hard-heres-a-pattern-that-works-4104af327210">https://cody-by-umar.medium.com/responsive-tables-are-hard-heres-a-pattern-that-works-4104af327210</a></p>
<p><a target="_blank" href="https://medium.com/@orami98/next-gen-web-animations-15-css-javascript-techniques-that-will-make-your-website-300-more-c85a948486ea">https://medium.com/@orami98/next-gen-web-animations-15-css-javascript-techniques-that-will-make-your-website-300-more-c85a948486ea</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/css-devtools-secrets-every-developer-should-master-2ffee437a4fb">https://javascript.plainenglish.io/css-devtools-secrets-every-developer-should-master-2ffee437a4fb</a></p>
<p><a target="_blank" href="https://medium.com/full-stack-forge/7-tailwindcss-utilities-youre-probably-underusing-a74896c7efde">https://medium.com/full-stack-forge/7-tailwindcss-utilities-youre-probably-underusing-a74896c7efde</a></p>
<p><a target="_blank" href="https://medium.com/full-stack-forge/this-one-css-trick-cleaned-up-my-entire-codebase-f0d3682b9a3c">https://medium.com/full-stack-forge/this-one-css-trick-cleaned-up-my-entire-codebase-f0d3682b9a3c</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/top-10-css-mistakes-even-experienced-devs-still-make-52577991a417">https://javascript.plainenglish.io/top-10-css-mistakes-even-experienced-devs-still-make-52577991a417</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/9-simple-css-tricks-that-make-your-website-feel-faster-689ac395a9d8">https://javascript.plainenglish.io/9-simple-css-tricks-that-make-your-website-feel-faster-689ac395a9d8</a></p>
<p><a target="_blank" href="https://medium.com/@Krishnajlathi/from-janky-to-smooth-the-css-scroll-trick-you-need-in-2025-9a1d0c942085">https://medium.com/@Krishnajlathi/from-janky-to-smooth-the-css-scroll-trick-you-need-in-2025-9a1d0c942085</a></p>
<p><a target="_blank" href="https://medium.com/full-stack-forge/how-to-use-css-dev-tools-like-a-senior-developer-e6e99bba6c19">https://medium.com/full-stack-forge/how-to-use-css-dev-tools-like-a-senior-developer-e6e99bba6c19</a></p>
<p><a target="_blank" href="https://medium.com/mern-mastery/the-secret-tailwind-hack-that-made-my-website-3x-faster-and-my-clients-finally-stopped-5e106b4faf9b">https://medium.com/mern-mastery/the-secret-tailwind-hack-that-made-my-website-3x-faster-and-my-clients-finally-stopped-5e106b4faf9b</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/the-one-css-trick-every-frontend-dev-shouldve-learned-years-ago-a20cb77b9542">https://javascript.plainenglish.io/the-one-css-trick-every-frontend-dev-shouldve-learned-years-ago-a20cb77b9542</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/stop-overusing-classes-use-these-css-attribute-selectors-instead-0a51b0e514a4">https://javascript.plainenglish.io/stop-overusing-classes-use-these-css-attribute-selectors-instead-0a51b0e514a4</a></p>
<p><a target="_blank" href="https://pixicstudio.medium.com/css-concepts-every-developer-should-know-f988b28d00d7">https://pixicstudio.medium.com/css-concepts-every-developer-should-know-f988b28d00d7</a></p>
]]></content:encoded></item><item><title><![CDATA[🔥 Mastering HTML]]></title><description><![CDATA[HTML is a tool for creating web pages. It offers a wide range of functions and a clear structure.
However, many developers have overlooked these features, even though they can greatly enhance web development efficiency and user experience.
But in thi...]]></description><link>https://blog.tuanhadev.tech/mastering-html</link><guid isPermaLink="true">https://blog.tuanhadev.tech/mastering-html</guid><category><![CDATA[HTML5]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Mon, 13 Jan 2025 09:47:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736586223544/4060d948-4525-4cb0-96cb-b36137fb8b20.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>HTML is a tool for creating web pages. It offers a wide range of functions and a clear structure.</p>
<p>However, many developers have overlooked these features, even though they can greatly enhance web development efficiency and user experience.</p>
<p>But in this article, I will show you the rest of the iceberg and what HTML is capable of.</p>
<h2 id="heading-semantic-html-isnt-just-for-screen-readers-its-a-superpower-you-are-probably-ignoring">Semantic HTML isn’t just for Screen Readers - It’s a superpower you are probably ignoring</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751538691390/1c504994-7140-4beb-8de9-de8512e4d4a8.webp" alt class="image--center mx-auto" /></p>
<p>Let me tell you something I have noticed after conducting dozens (maybe hundreds) of frontend interviews over the years — from junior devs to so-called “staff engineers“ with 10+ years under their belt.</p>
<blockquote>
<p><em>Most of them</em> know <em>semantic HTML exists.<br />Very few actually</em> understand <em>it.</em></p>
</blockquote>
<p>They can rattle off that <code>&lt;main&gt;</code>, <code>&lt;section&gt;</code>, and <code>&lt;aside&gt;</code> exist. Some even throw in a <code>&lt;figure&gt;</code> or <code>&lt;time&gt;</code> for good measure.</p>
<p>But when I ask:<br /><strong>“Why would you use a</strong> <code>&lt;section&gt;</code> <strong>instead of a</strong> <code>&lt;div&gt;</code><strong>?”</strong><br />…I usually get a pause, followed by a vague answer about “<strong><em>accessibility,</em></strong>” or “<strong><em>SEO,</em></strong>” or “<strong><em>structure</em></strong>.”</p>
<h3 id="heading-so-what-is-semantic-html-really">So, What is Semantic HTML —Really?</h3>
<p>Semantic HTML is about meaning, not appearance.</p>
<p>When you use semantic tags, you are telling the browser (and everything that reads HTML — search engines, screen readers, assistive tools, crawlers) what the content represents, not how it looks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751539130761/e068fdc3-c287-4d16-a9b8-762c1f6226df.webp" alt class="image--center mx-auto" /></p>
<p>And, guess what? They aren’t just fancier divs.</p>
<p>They play a critical role in how assistive tech, search engines, and even future developers understand your layout.</p>
<h3 id="heading-why-should-you-care-beyond-passing-a-lighthouse-audit">🎯 Why Should You Care? (Beyond Passing a Lighthouse Audit)</h3>
<p>Most frontend engineers treat semantic HTML like flossing.<br />They <em>know</em> they should do it… but they don’t really <em>feel</em> the urgency.</p>
<p>So let’s break down why it matters:</p>
<p><strong>1. Accessibility That Works Without JavaScript</strong></p>
<p>Screen readers like VoiceOver or NVDA rely on semantic structure to announce content properly.</p>
<p>A <code>&lt;button&gt;</code> is focusable, clickable, and works with keyboard input, <em>by default</em>. A <code>&lt;div&gt;</code> pretending to be a button? You’ll need to simulate all that behavior manually.</p>
<blockquote>
<p><strong><em>TL;DR:</em></strong> <em>If you don’t use semantic elements, you’re breaking accessibility — even if you didn’t mean to.</em></p>
</blockquote>
<p><strong>2. SEO That Understands Your Page</strong></p>
<p>Google’s crawler doesn’t just look at content — it looks at context. Semantic tags help define that context clearly.</p>
<ul>
<li><p>Using <code>&lt;article&gt;</code> tells Google, “this is a shareable, standalone chunk of info.”</p>
</li>
<li><p>Using <code>&lt;header&gt;</code> and <code>&lt;footer&gt;</code> makes the page easier to analyze.</p>
</li>
<li><p>Using <code>&lt;main&gt;</code> separates your real content from repetitive elements like navbars.</p>
</li>
</ul>
<p>Semantic HTML helps your content get discovered and ranked more accurately.</p>
<p><strong>3. Better Developer Experience</strong></p>
<p>Imagine coming back to a project after six months and seeing a mess of nested <code>&lt;div class="header"&gt;</code>, <code>&lt;div class="main"&gt;</code>, <code>&lt;div class="footer"&gt;</code>.</p>
<p>Now imagine seeing <code>&lt;header&gt;</code>, <code>&lt;main&gt;</code>, and <code>&lt;footer&gt;</code>.<br />Cleaner. Clearer. Faster to comprehend.</p>
<p>Semantic HTML is documentation built into your markup.</p>
<p><strong>4. Future-Proof and Standards-Based</strong></p>
<p>Browsers evolve. Assistive tech evolves. SEO rules change.</p>
<p>But semantic HTML is built on <em>standards</em>. Using the right tags today means your site is more likely to work correctly tomorrow, without chasing hacks.</p>
<h3 id="heading-real-world-analogy-html-is-the-script-of-the-web-play">🧪 Real-World Analogy: HTML Is the Script of the Web Play</h3>
<p>Think of your page as a play.</p>
<ul>
<li><p><code>&lt;header&gt;</code> is the opening scene.</p>
</li>
<li><p><code>&lt;main&gt;</code> is the core act.</p>
</li>
<li><p><code>&lt;aside&gt;</code> is like background commentary.</p>
</li>
<li><p><code>&lt;nav&gt;</code> is the stage direction.</p>
</li>
<li><p><code>&lt;footer&gt;</code> is the closing credits.</p>
</li>
</ul>
<p>If you just throw everything into <code>&lt;div&gt;</code>s, it’s like giving actors a blank script. They can try to perform it, but they won’t know what role they’re playing.</p>
<h2 id="heading-metadata-and-meta-tags-the-unsung-heroes-of-the-web">Metadata and Meta Tags: The Unsung Heroes of the Web</h2>
<p>When you think about building websites, your mind might go straight to HTML elements, beautiful CSS styles, or JavaScript interactivity. But there is a hidden layer of data that powers SEO, social sharing, browser behavior, and accessibility: metadata</p>
<h3 id="heading-what-is-the-metadata">What is the Metadata?</h3>
<p>Metadata is “data about data“. On the web, it describes the information about the web page rather than the visible content of the page itself.</p>
<p>Examples include:</p>
<ul>
<li><p>Page title</p>
</li>
<li><p>Description</p>
</li>
<li><p>Author</p>
</li>
<li><p>Language</p>
</li>
<li><p>Charset</p>
</li>
<li><p>Viewport settings</p>
</li>
<li><p>Social sharing info (Open Graph, Twitter Cards)</p>
</li>
</ul>
<p>This data is often invisible to users but essential for search engines, browsers, social media platforms, and assistive technologies.</p>
<h3 id="heading-what-are-meta-tags">What are Meta Tags?</h3>
<p>Meta Tags are the snippets of HTML placed inside the &lt;head/&gt; of your document to provide metadata. Here’s an example:</p>
<pre><code class="lang-xml"><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>Learn JavaScript Fast<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"A beginner-friendly guide to mastering JavaScript quickly."</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"author"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Jane Developer"</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">head</span>&gt;</span>
</code></pre>
<h3 id="heading-types-of-meta-tags-with-examples">Types Of Meta Tags (With Examples)</h3>
<ol>
<li><strong>Basic Meta Tags</strong></li>
</ol>
<p><strong>✅ Title</strong></p>
<p>Defines the page title shown on the browser tab and in search results.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My Awesome Blog<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
</code></pre>
<p><strong>✅ Description</strong></p>
<p>Helps search engines and social platforms understand what your page is about.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Explore the best web development tips and tricks."</span>&gt;</span>
</code></pre>
<p><strong>✅ Author</strong></p>
<p>Credits the content creator.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"author"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"John Doe"</span>&gt;</span>
</code></pre>
<ol start="2">
<li><strong>Viewport Meta Tag (Responsive Design)</strong></li>
</ol>
<p>Makes your website mobile-friendly.</p>
<pre><code class="lang-xml"><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>
</code></pre>
<ol start="3">
<li><strong>Charset</strong></li>
</ol>
<p>Sets the character encoding. UTF-8 is standard for modern websites.</p>
<pre><code class="lang-xml"><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>
</code></pre>
<ol start="4">
<li><strong>Robots Meta Tag</strong></li>
</ol>
<p>Tells search engines how to crawl or index your page.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"robots"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"index, follow"</span>&gt;</span>
<span class="hljs-comment">&lt;!-- or --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"robots"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"noindex, nofollow"</span>&gt;</span>
</code></pre>
<ol start="5">
<li><strong>Social Metadata</strong></li>
</ol>
<p><strong>Open Graph (Facebook, LinkedIn)</strong></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:title"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Ultimate JavaScript Guide"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Everything you need to become a JavaScript pro."</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://example.com/thumbnail.jpg"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:url"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://example.com/javascript-guide"</span>&gt;</span>
</code></pre>
<p><strong>Twitter Cards</strong></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:card"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"summary_large_image"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:title"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"JavaScript Crash Course"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Get started with JavaScript the right way."</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"twitter:image"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://example.com/twitter-thumbnail.jpg"</span>&gt;</span>
</code></pre>
<ol start="6">
<li><strong>Other Useful Meta Tags</strong></li>
</ol>
<p><strong>Language</strong></p>
<pre><code class="lang-xml"><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>
</code></pre>
<p><strong>HTTP-Equiv (Auto-refresh, page redirect, cache control)</strong></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"refresh"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"30"</span>&gt;</span>
</code></pre>
<p><strong>Theme Color (Mobile browsers)</strong></p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"theme-color"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"#ffffff"</span>&gt;</span>
</code></pre>
<ol start="7">
<li><strong>SEO &amp; Best Practices</strong></li>
</ol>
<ul>
<li><p>Always write a <strong>unique title and description</strong> for each page.</p>
</li>
<li><p>Use <strong>Open Graph</strong> and <strong>Twitter Cards</strong> for social sharing.</p>
</li>
<li><p>Don’t forget the <strong>viewport</strong> tag for responsive design.</p>
</li>
<li><p>Avoid duplicate metadata tags — they confuse crawlers.</p>
</li>
<li><p>Use <code>&lt;meta charset="UTF-8"&gt;</code> as early as possible in <code>&lt;head&gt;</code>.</p>
</li>
</ul>
<h2 id="heading-html-tips-you-must-know-about">HTML Tips You Must Know About</h2>
<h3 id="heading-lock-background-content-with-inert">Lock Background Content with inert</h3>
<p>When a modal is open, the rest of the page shouldn’t be clickable.</p>
<p><code>inert</code> does this in one line while also making it inaccessible to screen readers.</p>
<pre><code class="lang-javascript">&lt;div id=<span class="hljs-string">"main-content"</span> inert&gt;
  &lt;!-- your page stuff --&gt;
&lt;/div&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">dialog</span> <span class="hljs-attr">open</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dialog</span>&gt;</span></span>
</code></pre>
<pre><code class="lang-javascript">[inert] {
  <span class="hljs-attr">opacity</span>: <span class="hljs-number">0.5</span>;
}
</code></pre>
<p><strong>Real Example 1: Disable a Sidebar While a Dropdown Is Open</strong></p>
<p>Great for dashboards or apps with side menus</p>
<pre><code class="lang-javascript">&lt;aside id=<span class="hljs-string">"sidebar"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Menu Item<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Menu Item<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
&lt;/aside&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"dropdown"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dropdown"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"toggle"</span>&gt;</span>Open Settings<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"panel"</span> <span class="hljs-attr">hidden</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Settings panel content<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>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> sidebar = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'sidebar'</span>);
<span class="hljs-keyword">const</span> toggle = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'toggle'</span>);
<span class="hljs-keyword">const</span> panel = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.panel'</span>);

toggle.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> isOpen = !panel.hidden;
  panel.hidden = isOpen;
  sidebar.toggleAttribute(<span class="hljs-string">'inert'</span>, !isOpen);
});
</code></pre>
<p><strong>Real Example 2: Lock a Form While It’s Submitting</strong></p>
<p>Perfect for preventing double form submissions</p>
<pre><code class="lang-javascript">&lt;form id=<span class="hljs-string">"userForm"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">required</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Save<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"loading"</span> <span class="hljs-attr">hidden</span>&gt;</span>Saving…<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> form = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'userForm'</span>);
<span class="hljs-keyword">const</span> loading = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'loading'</span>);

form.addEventListener(<span class="hljs-string">'submit'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  e.preventDefault();

  form.setAttribute(<span class="hljs-string">'inert'</span>, <span class="hljs-string">''</span>);
  loading.hidden = <span class="hljs-literal">false</span>;

  <span class="hljs-comment">// Fake submit delay</span>
  <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
    form.removeAttribute(<span class="hljs-string">'inert'</span>);
    loading.hidden = <span class="hljs-literal">true</span>;
    alert(<span class="hljs-string">'Saved!'</span>);
  }, <span class="hljs-number">1500</span>);
});
</code></pre>
<h3 id="heading-replace-heavy-js-modals-with-ltdialoggt">Replace Heavy JS Modals with &lt;dialog&gt;</h3>
<p><code>&lt;dialog&gt;</code> is one of my favorite HTML discoveries.</p>
<p>It gives you a native modal with proper accessibility built in.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> dialog = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'myDialog'</span>);
dialog.showModal(); <span class="hljs-comment">// makes page inert + adds backdrop</span>
</code></pre>
<p>Closing it is just as easy:</p>
<pre><code class="lang-javascript">dialog.close();
</code></pre>
<p>You don’t need external libraries anymore.</p>
<p>And you can style the backdrop:</p>
<pre><code class="lang-javascript">dialog::backdrop {
  <span class="hljs-attr">background</span>: rgba(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.5</span>);
}
</code></pre>
<p>Your UI becomes cleaner, faster, and less buggy.</p>
<h3 id="heading-the-element">The <code>&lt;template /&gt;</code> Element</h3>
<p>The <code>&lt;template /&gt;</code> element is one of those hidden gems in HTML5 that many developers haven’t fully explored.</p>
<p>Without any need for frameworks like React, it serves as a container for holding the HTML content that isn’t rendered on the page immediately. Instead, this content can be cloned and inserted into the DOM later, usually via Javascript.</p>
<p>It’s ideal for scenarios where you need to render content dynamically, like in single-page applications (SPAs) or when your component gets reused multiple times.</p>
<p>Here’s how it works:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"card-template"</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">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">""</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Image"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-img"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-text"</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">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">const</span> template = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'card-template'</span>);
    <span class="hljs-keyword">const</span> clone = template.content.cloneNode(<span class="hljs-literal">true</span>);
    clone.querySelector(<span class="hljs-string">'.card-img'</span>).src = <span class="hljs-string">'image.jpg'</span>;
    clone.querySelector(<span class="hljs-string">'.card-text'</span>).textContent = <span class="hljs-string">'This is a dynamic card!'</span>;
    <span class="hljs-built_in">document</span>.body.appendChild(clone);
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>In this example, we have used the <code>&lt;template /&gt;</code> element to create a reusable card component that can be easily cloned and customized by Javascript.</p>
<h3 id="heading-the-element-for-responsive-images">The <code>&lt;picture /&gt;</code> Element for Responsive Images</h3>
<p>The <code>&lt;picture /&gt;</code> element is designed to help developers display different images based on different conditions, such as screen size or resolution.</p>
<p>This feature makes media queries in CSS almost obsolete.</p>
<p>Here’s how you can implement the <code>&lt;picture /&gt;</code> element:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">picture</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">"image-small.jpg"</span> <span class="hljs-attr">media</span>=<span class="hljs-string">"(max-width: 600px)"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">"image-large.jpg"</span> <span class="hljs-attr">media</span>=<span class="hljs-string">"(min-width: 601px)"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"image-default.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Responsive Image"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">picture</span>&gt;</span>
</code></pre>
<p>In this example, we have defined different image sources for different screen sizes, ensuring that the appropriate image is loaded depending on the user’s device.</p>
<h3 id="heading-the-element-for-enhanced-input-fields">The <code>&lt;datalist /&gt;</code> Element for Enhanced Input Fields</h3>
<p>The <code>&lt;datalist /&gt;</code> element is a great addition to HTML5, providing a way to offer predefined options within an input field.</p>
<p>It creates a drop-down list of suggestions that users can choose from, making forms more interactive and user-friendly.</p>
<p>Let’s see how to use the <code>&lt;datalist /&gt;</code> element in a search input field:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">list</span>=<span class="hljs-string">"fruits"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">datalist</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"fruits"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"apple"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"orange"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"banana"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">datalist</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736593709185/0b11235c-0ae3-46c1-b6c1-f87d20aa2ee7.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-element-for-display-calculation-results">The <code>&lt;output /&gt;</code> Element for Display Calculation Results</h3>
<p>The <code>&lt;output /&gt;</code> element is a great tool in HTML5 for displaying the results of calculations or user actions.</p>
<p>It’s particularly useful in interactive forms or web applications where you want to show immediate feedback without relying on Javascript.</p>
<p>Here is how the <code>&lt;output /&gt;</code> element can be used:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">oninput</span>=<span class="hljs-string">"result.value=parseInt(a.value)+parseInt(b.value)"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"a"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"50"</span>&gt;</span> +
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"b"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"100"</span>&gt;</span>
    = <span class="hljs-tag">&lt;<span class="hljs-name">output</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"result"</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"a b"</span>&gt;</span>150<span class="hljs-tag">&lt;/<span class="hljs-name">output</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>In this example, the <code>&lt;output /&gt;</code> element has displayed the sum of two numbers in real time.</p>
<h3 id="heading-creating-contact-links">Creating Contact Links</h3>
<p>Create clickable emails, phone calls, and SMS links using HTML:</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- Email link --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"mailto:name@example.com"</span>&gt;</span> Send Email <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Phone call link --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"tel:+1234567890"</span>&gt;</span> Call Us <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>

<span class="hljs-comment">&lt;!-- SMS link --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"sms:+1234567890"</span>&gt;</span> Send SMS <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<h3 id="heading-creating-collapsible-content">Creating Collapsible Content - <code>&lt;details /&gt;</code></h3>
<p>You can use the <code>&lt;details&gt;</code> and <code>&lt;summary&gt;</code> tags, when you want to include collapsible content on your web page.</p>
<p>The <code>&lt;details /&gt;</code> tag creates a container for hidden content, while the <code>&lt;summary /&gt;</code> tag provides a clickable label to toggle the visibility of that content.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">details</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">summary</span>&gt;</span>Who to follow?<span class="hljs-tag">&lt;/<span class="hljs-name">summary</span>&gt;</span>
    Halim Shams
<span class="hljs-tag">&lt;/<span class="hljs-name">details</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736593773110/bed3a4d4-77e9-4575-bde1-b6d5b63125c2.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-utilizing-semantic-elements">Utilizing Semantic Elements</h3>
<p>The elements mentioned above fall under an umbrella term: semantic HTML. Semantic HTML gives meaning to your HTML content—not only to users but also to browsers, crawlers, and accessibility tools.</p>
<p>Not everyone can see the screen or use devices such as a mouse to navigate the web. Instead, they rely on assistant technologies to interpret the content.</p>
<p>Also, search engines can find relevant content more easily by traversing through semantic HTML. That’s why it should be one of your top priorities when you are building a website.</p>
<p>You also don’t want your website to be <a target="_blank" href="https://www.scottohara.me/blog/2022/01/20/divisive.html">just a bunch of divs</a> because div elements don't mean anything to the browser in terms of content—for a browser, they’re just a division element to separate the content.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736599438172/9b2ea20c-9229-4bef-babc-ffb161eecf43.png" alt class="image--center mx-auto" /></p>
<p>Choose semantic elements over non-semantic elements for your websites. They make your code meaningful and improve structure, accessibility, and SEO.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736590810394/7a17001a-1ab6-4687-916e-bc83956673a2.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-grouping-form-elements">Grouping Form Elements - <code>&lt;fieldset&gt;</code></h3>
<p>Use the <code>&lt;fieldset&gt;</code> tag to group related elements in a form and the <code>&lt;legend&gt;</code> tag with <code>&lt;fieldset&gt;</code> to define a title for the <code>&lt;fieldset&gt;</code> tag.</p>
<p>This is useful for creating more efficient and accessible forms:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">fieldset</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">legend</span>&gt;</span>Personal details<span class="hljs-tag">&lt;/<span class="hljs-name">legend</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"firstname"</span>&gt;</span>First name:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"firstname"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"firstname"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <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">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"contact"</span>&gt;</span>Contact:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"contact"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"contact"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Submit"</span> /&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">fieldset</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<h3 id="heading-enhancing-dropdown-menus">Enhancing Dropdown Menus - <code>&lt;optgroup&gt;</code></h3>
<p>You can use the <code>&lt;optgroup&gt;</code> tag to group related options in a <code>&lt;select&gt;</code> HTML tag.</p>
<p>This can be used when you are working with a large dropdown menu and a long list of options:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">select</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">optgroup</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Fruits"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>Apple<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>Banana<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>Mango<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">optgroup</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">optgroup</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Vegetables"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>Tomato<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>Broccoli<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>Carrot<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">optgroup</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
</code></pre>
<h3 id="heading-display-text-as-subscript-and-superscript">Display Text as Subscript and Superscript</h3>
<p>The <code>&lt;sub&gt;</code> and <code>&lt;sup&gt;</code> elements can be used to display the text as subscript and superscript respectively:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736591154286/1fcb5291-3b3f-485b-b900-c59841ce10c0.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-defining-base-url-for-relative-links">Defining Base URL for Relative Links</h3>
<p>You can use the <code>&lt;base&gt;</code> tag to define the base URL for all relative URLs on the web page.</p>
<p>This is handy when you want to create shared starting points for all relative URLs on a web page, making it easier to navigate and load resources.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">base</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://shefali.dev"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</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">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/blog"</span>&gt;</span>Blogs<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">"/get-in-touch"</span>&gt;</span>Contact<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<h3 id="heading-yga"><code>&lt;mark /&gt;</code></h3>
<p>&lt;mark /&gt; is a tag used to highlight or mark a part of a text. This tag supports all HTML global attributes, the default color is black with a yellow background color.</p>
<pre><code class="lang-xml"><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">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">p</span>&gt;</span>
            in this paragraph, there is a text
            <span class="hljs-comment">&lt;!-- 
                by default =&gt; (
                    color: black;                
                    background-color: yellow;
                )
             --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">mark</span>&gt;</span>highlighted<span class="hljs-tag">&lt;/<span class="hljs-name">mark</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">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736591828464/c2da681e-47e4-4756-b817-45b9187245d3.png" alt class="image--center mx-auto" /></p>
<p>You can change the yellow color like this:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">mark</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"background-color:green"</span>&gt;</span>highlighted<span class="hljs-tag">&lt;/<span class="hljs-name">mark</span>&gt;</span>
</code></pre>
<p>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736591878226/417a5add-fb95-4b60-bd7a-c9ab2aefb310.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-yga-1"><code>&lt;address /&gt;</code></h3>
<p><code>&lt;address /&gt;</code> is a tag that displays contact information like the email and phone number of the author of a document or an article, additionally, it supports all HTML global attributes.</p>
<pre><code class="lang-xml"><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">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">address</span>&gt;</span>
            Posted by
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://t.me/AyaBouchiha"</span>&gt;</span> Aya Bouchiha <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
            Email Address:
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"mailto:developer.aya.b@gmail.com"</span>&gt;</span>
                developer.aya.b@gmail.com
            <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
            Phone Number:
            <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"tel:+212600000000"</span>&gt;</span>+212600000000 <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
            Morocco, Azemmour
        <span class="hljs-tag">&lt;/<span class="hljs-name">address</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>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736592032743/2f8965db-e2b2-4fcb-944d-266d17575189.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-yga-2"><code>&lt;noscript /&gt;</code></h3>
<p><code>&lt;noscript /&gt;</code>: This tag can be inside a head or a body tag, it displays alternate HTML contents if the script type is not supported or if the browser has scripting disabled. if not the tag will not display the alternate HTML. But you have to be careful, &lt;noscript /&gt; tag sometimes impacts the SEO due to writing the same sentence on every page of your website… <a target="_blank" href="https://northcutt.com/seo/how-the-noscript-tag-impacts-seo-hint-be-very-careful/">solutions &amp; more details</a>.</p>
<pre><code class="lang-xml"><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">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
            alert(<span class="hljs-string">"javascript is supported in your browser :)"</span>);
        </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">noscript</span>&gt;</span> Javascript is not supported in your browser :( <span class="hljs-tag">&lt;/<span class="hljs-name">noscript</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>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736592381198/ca3b0c91-b154-49aa-8833-bd3cca18781b.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-yga-3"><code>&lt;time /&gt;</code></h3>
<p><code>&lt;time /&gt;</code>: represent a specific period in time. It may include the date time attribute to translate dates into a machine-readable format, allowing for better search engine results or custom features such as reminders. (support all HTML global attributes). <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time">more details</a></p>
<pre><code class="lang-xml"><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">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">p</span>&gt;</span>
            The next meeting will be held on 
            <span class="hljs-tag">&lt;<span class="hljs-name">time</span> <span class="hljs-attr">datetime</span>=<span class="hljs-string">"2021-11-25"</span>&gt;</span>
                Nov 25
            <span class="hljs-tag">&lt;/<span class="hljs-name">time</span>&gt;</span>
            in Rabat
        <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>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736592654062/2a3d39f8-4b73-49c9-9eca-57047043fa88.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-yga-4"><code>&lt;var /&gt;</code></h3>
<p>&lt;var /&gt;: supports all HTML global attributes and indicates the name of mathematical variables such as x and y, by default its text content is italic.</p>
<pre><code class="lang-xml"><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">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">div</span>&gt;</span>
            <span class="hljs-comment">&lt;!--
                by default (
                    var {
                        font-style: italic;
                    }
                )
            --&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Ex:1 solve this equation:<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">var</span>&gt;</span>4x<span class="hljs-tag">&lt;/<span class="hljs-name">var</span>&gt;</span> + <span class="hljs-tag">&lt;<span class="hljs-name">var</span>&gt;</span>2y<span class="hljs-tag">&lt;/<span class="hljs-name">var</span>&gt;</span> = 12
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</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>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736593532147/d338d49d-f7e0-4bd5-9fc1-cd611dd75fec.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-tag">The <code>&lt;code/&gt;</code> Tag</h3>
<p>The <code>&lt;code /&gt;</code> tag is extremely useful for displaying code blocks. You could use CSS and a normal &lt;p&gt; element to make it look like a code block, but why do that when the &lt;code&gt; tag exists for this exact use case?</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>In JS we have <span class="hljs-tag">&lt;<span class="hljs-name">code</span>&gt;</span>console.log("Heyo!")<span class="hljs-tag">&lt;/<span class="hljs-name">code</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736594361195/033f3706-3ac1-4b82-8756-abda259d3f77.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-tag-1">The <code>&lt;kbd /&gt;</code> Tag</h3>
<p>It’s similar to the code tag, we have the <code>&lt;kbd /&gt;</code> tag, also known as the keyboard tag. It is used to showcase keyboard input.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Press <span class="hljs-tag">&lt;<span class="hljs-name">kbd</span>&gt;</span>Ctrl<span class="hljs-tag">&lt;/<span class="hljs-name">kbd</span>&gt;</span> to start.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736594197671/2a4a9d18-46a8-496d-9c63-af6a6cbcbd16.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-tag-2">The <code>&lt;abbr&gt;</code> Tag</h3>
<p>First up, the <code>&lt;abbr&gt;</code> tag, also known as the abbreviation tag. This one is used when you want to display the meaning of an acronym or abbreviation.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">abbr</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"A type of snake"</span>&gt;</span>Python<span class="hljs-tag">&lt;/<span class="hljs-name">abbr</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736594600251/4cc116f9-74c8-411a-90c8-3b6753155c30.gif" alt class="image--center mx-auto" /></p>
<p>Notice the title attribute used with the <code>&lt;abbr&gt;</code> tag. This works with every tag. Now, when you hover your cursor over that abbreviation, it shows the title that you set. I recommend putting this on buttons or icons for enhanced accessibility.</p>
<h3 id="heading-the-element-1">The <code>&lt;aside&gt;</code> element</h3>
<p>You can use this element for any content not directly related to the page's main content. It works well for displaying advertisements, related posts, promotional content, blockquotes, nav elements, and so on.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>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>&gt;</span>This post is about a breed of dogs.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">aside</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Learn more about cats.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">aside</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
</code></pre>
<p>For example, in the above snippet, the post is mainly about dogs and their breeds. But if you wrote an article about cats and you wanted to link to it from the dog article, then you could use an <code>aside</code> element to mention it. The content in the <code>aside</code> element can be tangentially related to the page.</p>
<p>The HTML specification provides <a target="_blank" href="https://html.spec.whatwg.org/multipage/sections.html#the-aside-element">some good examples of how to use the <code>&lt;aside&gt;</code> element</a>.</p>
<h3 id="heading-the-element-2">The <code>&lt;search&gt;</code> Element</h3>
<p>You can use the <code>&lt;search&gt;</code> element as a container for elements dealing with search or filtering. For example, a form sending a POST request to get search results or a search component relying on Javascript or filtering.</p>
<pre><code class="lang-xml">// search component relying on JavaScript
<span class="hljs-tag">&lt;<span class="hljs-name">search</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"searchInput"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"results"</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">search</span>&gt;</span>
</code></pre>
<p>Here is another example:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">search</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"search.js"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"searchInput"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Search<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">search</span>&gt;</span>
</code></pre>
<p>In both of the above examples, the elements wrapped within the <code>search</code> element contributes to a site's search functionality.</p>
<p>You should use this element because it provides semantic values to the browser and accessibility tools such as screen readers.</p>
<h3 id="heading-the-element-3">The <code>&lt;progress&gt;</code> element</h3>
<p>As the name suggests, the native progress element in HTML tracks the progress of a task.</p>
<p>You can use this element in two ways: determinately and indeterminately. A determinate progress bar knows where it currently is, and if the max value is specified, you can also figure out how much more is left.</p>
<p>To create a determinate progress bar, you need to specify the value attribute. The default range of the value is from 0.0 to 1.0. But you can also specify the custom max value which has to be a valid floating point number.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">progress</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"0"</span>&gt;</span>0%<span class="hljs-tag">&lt;/<span class="hljs-name">progress</span>&gt;</span>
<span class="hljs-comment">&lt;!-- or --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">progress</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">max</span>=<span class="hljs-string">"100"</span>&gt;</span>0%<span class="hljs-tag">&lt;/<span class="hljs-name">progress</span>&gt;</span>
</code></pre>
<h3 id="heading-and"><code>&lt;map&gt;</code> and <code>&lt;area&gt;</code></h3>
<p><code>&lt;map&gt;</code> and <code>&lt;area&gt;</code> — powerful combo to create clickable areas in images:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736599620692/2ec8fda3-a2ec-4b96-ac00-3f9cfc0d680d.webp" alt class="image--center mx-auto" /></p>
<p>We call clickable images like these image maps:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736599691593/b77e918d-141f-4fcf-a413-b65faefe2d5a.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-not-using-html-entitieshttpswwww3schoolscomhtmlhtmlentitiesasp">Not using <a target="_blank" href="https://www.w3schools.com/html/html_entities.asp">HTML Entities</a></h3>
<p>Please don't copy and paste symbols like this: ™, ℠, ®, and ©.</p>
<p>Instead, use these:</p>
<pre><code class="lang-typescript">&amp;nbsp; -&gt; <span class="hljs-keyword">for</span> blank space
&amp;reg; -&gt; <span class="hljs-keyword">for</span> trademark
&amp;copy; -&gt; <span class="hljs-keyword">for</span> copyright
and etc.
</code></pre>
<h2 id="heading-powerful-html-attributes">Powerful HTML Attributes</h2>
<h3 id="heading-spellcheck">Spellcheck</h3>
<p>This attribute ensures that the browser checks spelling within specific elements, such as input fields or text areas, without requiring Javascript. It’s particularly useful for forms or content where accuracy matters.</p>
<pre><code class="lang-xml">   <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">spellcheck</span>=<span class="hljs-string">"true"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
</code></pre>
<h3 id="heading-download">Download</h3>
<p>The <code>download</code> attribute allows users to download resources directly when clicking on a link. It’s handy for providing downloadable content like images, documents, and media files without Javascript.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"path/to/file.pdf"</span> <span class="hljs-attr">download</span>&gt;</span>Download PDF<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<h3 id="heading-video-thumbnail-poster">Video Thumbnail (Poster)</h3>
<p>By using the <code>poster</code> attribute within the <code>&lt;video&gt;</code> element, you can specify an image to display as a placeholder before the video starts playing. This mimics the functionality of a video thumbnail, enhancing user experience.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">video</span> <span class="hljs-attr">controls</span> <span class="hljs-attr">poster</span>=<span class="hljs-string">"path/to/thumbnail.jpg"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"path/to/video.mp4"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"video/mp4"</span>&gt;</span>
       Your browser does not support the video tag.
   <span class="hljs-tag">&lt;/<span class="hljs-name">video</span>&gt;</span>
</code></pre>
<h3 id="heading-translate">Translate</h3>
<p>Employing the <code>translate</code> attribute, you can specify whether an element’s content should be translated when a web page is translated into another language. Setting it to “no“ preserves the original content, useful for brand names or specific terms.</p>
<pre><code class="lang-xml">   <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">translate</span>=<span class="hljs-string">"no"</span>&gt;</span>Your Company Name<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
</code></pre>
<h3 id="heading-autocomplete">Autocomplete</h3>
<p>The <code>autocomplete</code> attribute enables or disables the autocomplete functionality for input fields, providing control over whether the browser should suggest previously entered values. This can enhance user convenience and streamline form submission.</p>
<pre><code class="lang-xml">   <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">autocomplete</span>=<span class="hljs-string">"on"</span>&gt;</span>
</code></pre>
<h3 id="heading-form-validation-with-html5-attributes">Form Validation With HTML5 Attributes</h3>
<p>HTML5 has introduced built-in form validation attributes such as <code>required</code>, <code>pattern</code>, <code>minlength</code>, and <code>maxlength</code>.</p>
<p>These attributes have allowed you to enforce input rules directly in the HTML, reducing the need for complex Javascript validation.</p>
<p>Here’s an example of a form with HTML5 validation:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"username"</span>&gt;</span>Username:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">required</span> <span class="hljs-attr">minlength</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">maxlength</span>=<span class="hljs-string">"20"</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>Email:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
    <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">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">required</span> <span class="hljs-attr">pattern</span>=<span class="hljs-string">"[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Submit"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<h3 id="heading-supporting-multiple-selections">Supporting Multiple Selections</h3>
<p>You can use the <code>multiple</code> attributes with the <code>&lt;input&gt;</code> and <code>&lt;select&gt;</code> elements to allow users to select multiple values at once.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-attr">multiple</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">multiple</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"java"</span>&gt;</span>Java<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"javascript"</span>&gt;</span>JavaScript<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"typescript"</span>&gt;</span>TypeScript<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"rust"</span>&gt;</span>Rust<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
</code></pre>
<h3 id="heading-control-image-loading">Control Image Loading</h3>
<p>The <code>loading</code> attribute of the <code>&lt;img&gt;</code> element can be used to control how the browser loads the image. It has three values: “eager“, “lazy“, and “auto“.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"picture.jpg"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span>
</code></pre>
<h3 id="heading-enabling-content-editing">Enabling Content Editing</h3>
<p>Use the <code>contenteditable</code> attribute to specify whether the element’s content is editable or not.</p>
<p>It allows users to modify the content within the element.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">contenteditable</span>=<span class="hljs-string">"true"</span>&gt;</span>
   You can edit this content.
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h3 id="heading-ensuring-accessibility">Ensuring Accessibility</h3>
<p>The <code>alt</code> attribute specifies the alternate text for an image if the image can not be displayed.</p>
<p>Always include descriptive alt attributes for images to improve accessibility and SEO.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"picture.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Description for the image"</span>&gt;</span>
</code></pre>
<h3 id="heading-defining-target-behavior-for-links">Defining Target Behavior for Links</h3>
<p>You can use the <code>target</code> attribute to specify where a linked resource will be displayed when clicked.</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- Opens in the same frame --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://shefali.dev"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_self"</span>&gt;</span>Open<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Opens in a new window or tab --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://shefali.dev"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>Open<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Opens in the parent frame --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://shefali.dev"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_parent"</span>&gt;</span>Open<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Opens in the full body of the window --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://shefali.dev"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_top"</span>&gt;</span>Open<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Opens in the named frame --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://shefali.dev"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"framename"</span>&gt;</span>Open<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<h3 id="heading-providing-additional-information">Providing Additional Information</h3>
<p>The <code>title</code> can be used to provide additional information about an element when users hover on it.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"World Health Organization"</span>&gt;</span>WHO<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<h3 id="heading-accepting-specific-file-types">Accepting Specific File Types</h3>
<p>You can use the <code>accept</code> attribute to specify the types of files accepted by the server (only for file types). This is used with the <code>&lt;input&gt;</code> element.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-attr">accept</span>=<span class="hljs-string">"image/png, image/jpeg"</span> /&gt;</span>
</code></pre>
<h3 id="heading-optimizing-video-loading">Optimizing Video Loading</h3>
<p>You can make video files load faster for smoother playback by using the <code>preload</code> attribute with <code>&lt;video&gt;</code> element.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">video</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"video.mp4"</span> <span class="hljs-attr">preload</span>=<span class="hljs-string">"auto"</span>&gt;</span>
   Your browser does not support the video tag.
<span class="hljs-tag">&lt;/<span class="hljs-name">video</span>&gt;</span>
</code></pre>
<h3 id="heading-capture-attribute">Capture Attribute</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736760395133/fb55d874-c068-4df7-a62d-692ea14baf5a.webp" alt class="image--center mx-auto" /></p>
<p>It is used to determine which source to use when receiving media (video, photo, audio) files from the user.</p>
<p>It is usually used with the input element and its value allows users to capture content directly by opening their device’s camera, microphone, or other media sources.</p>
<p>It takes two values to control input: <code>capture:user</code> uses the user’s front camera or micro as an input, <code>capture:environment</code> uses the user’s back camera to capture the input data.</p>
<h3 id="heading-auto-refresh">Auto Refresh</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736760944161/80422542-6e21-4289-8155-10e096dae572.webp" alt class="image--center mx-auto" /></p>
<p>You can set your website to refresh after a given amount of time from the head tag. You just need to set up that in the head tag. The code above refreshes the page every 10 seconds.</p>
<h2 id="heading-99-of-developers-dont-know-these-aria-attributes-exist">99% of Developers Don’t Know These ARIA Attributes Exist</h2>
<p>Accessibility is no longer optional, and honestly, these tools we have now have made it easier to build websites that work with everyone. RIA attributes are at the heart of this, and they are much more powerful than most developers realize.</p>
<h3 id="heading-what-exactly-are-aria-attributes">What Exactly Are ARIA Attributes?</h3>
<p>ARIA stands for <code>Accessible Rich Internet Applications</code>. At its core, <code>ARIA</code> give you a way to communicate with assistive technologies like screen readers. When you build a custom dropdown or a fancy model, your code knows what it is, but screen readers don’t. <code>ARIA</code> fill that gap.</p>
<p>Think of it this way, you create a beautiful tabbed interface using <code>divs</code> and <code>CSS</code>. Visually, it’s perfect, but someone using a screen reader has no idea of those tabs. Add the right <code>ARIA attributes</code>, and suddenly, a screen reader understands the entire integration pattern.</p>
<h3 id="heading-why-this-actually-matters">Why This Actually Matters?</h3>
<p>Over a billion people worldwide have some form of disability, which is approximately 15-16% of the global population. Many rely on screen readers, voice control, keyboard navigation, and other assistive technologies just to use the web. Without proper ARIA implementation, your site might look amazing but completely unusable to them</p>
<p>Accessibility isn’t just about compliance and avoiding lawsuits (though those are real concerns). Accessible websites are better websites. They are more semantic, easy to navigate with the keyboard, have better structures, and perform better in search engines as well.</p>
<h3 id="heading-the-first-rule-of-aria">The First Rule of ARIA</h3>
<p>Before we go deeply into this massive list, you need to know this: <strong>semantic HTML always comes first.</strong></p>
<p><mark>Don’t use </mark> <code>&lt;div role="button"&gt;</code> <mark>when </mark> <code>&lt;button&gt;</code> <mark>exists.</mark> Don't reinvent the wheel with ARIA when HTML already does the job. Native elements come with built-in accessibility, keyboard support, and expected behaviors. ARIA is for filling the gaps when HTML falls short.</p>
<h3 id="heading-practical-examples-youll-use-daily">Practical Examples You’ll Use Daily</h3>
<p>Here’s how this stuff works in real code.</p>
<p><strong>Example 1: Custom Toggle Button</strong></p>
<pre><code class="lang-typescript">&lt;div role=<span class="hljs-string">"button"</span> 
     tabindex=<span class="hljs-string">"0"</span> 
     aria-pressed=<span class="hljs-string">"false"</span>
     onclick=<span class="hljs-string">"this.setAttribute('aria-pressed', this.getAttribute('aria-pressed') === 'false')"</span>&gt;
  Dark Mode&lt;/div&gt;
</code></pre>
<p><strong>Example 2: Accessible Modal Dialog</strong></p>
<pre><code class="lang-typescript">&lt;div role=<span class="hljs-string">"dialog"</span> 
     aria-modal=<span class="hljs-string">"true"</span> 
     aria-labelledby=<span class="hljs-string">"dialog-title"</span>
     aria-describedby=<span class="hljs-string">"dialog-desc"</span>&gt;
  &lt;h2 id=<span class="hljs-string">"dialog-title"</span>&gt;Delete Item?&lt;/h2&gt;
  &lt;p id=<span class="hljs-string">"dialog-desc"</span>&gt;This action cannot be undone.&lt;/p&gt;
  &lt;button&gt;Delete&lt;/button&gt;
  &lt;button&gt;Cancel&lt;/button&gt;
&lt;/div&gt;
</code></pre>
<p><strong>Example 3: Form Validation</strong></p>
<pre><code class="lang-typescript">&lt;label <span class="hljs-keyword">for</span>=<span class="hljs-string">"email"</span>&gt;Email Address&lt;/label&gt;
&lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"email"</span> 
       id=<span class="hljs-string">"email"</span> 
       aria-required=<span class="hljs-string">"true"</span>
       aria-invalid=<span class="hljs-string">"true"</span> 
       aria-describedby=<span class="hljs-string">"email-error"</span>&gt;
&lt;span id=<span class="hljs-string">"email-error"</span> role=<span class="hljs-string">"alert"</span>&gt;
  Please enter a valid email address
&lt;/span&gt;
</code></pre>
<p><strong>Example 4: Expandable Section</strong></p>
<pre><code class="lang-typescript">&lt;button aria-expanded=<span class="hljs-string">"false"</span> aria-controls=<span class="hljs-string">"content-panel"</span>&gt;
  Show More Details
&lt;/button&gt;
&lt;div id=<span class="hljs-string">"content-panel"</span> hidden&gt;
  Additional content here...
&lt;/div&gt;
</code></pre>
<p><strong>Example 5: Live Search Results</strong></p>
<pre><code class="lang-typescript">&lt;label <span class="hljs-keyword">for</span>=<span class="hljs-string">"search"</span>&gt;Search Products&lt;/label&gt;
&lt;input id=<span class="hljs-string">"search"</span> 
       <span class="hljs-keyword">type</span>=<span class="hljs-string">"search"</span> 
       aria-controls=<span class="hljs-string">"results"</span>
       aria-describedby=<span class="hljs-string">"results-count"</span>&gt;
&lt;div id=<span class="hljs-string">"results"</span> 
     role=<span class="hljs-string">"region"</span> 
     aria-live=<span class="hljs-string">"polite"</span>&gt;
  &lt;span id=<span class="hljs-string">"results-count"</span>&gt;<span class="hljs-number">12</span> products found&lt;/span&gt;
  &lt;!-- Results list here --&gt;
&lt;/div&gt;
</code></pre>
<h2 id="heading-html5-semantic-tags-7-elements-you-are-probably-using-wrong">HTML5 Semantic Tags: 7 Elements You Are Probably Using Wrong</h2>
<p>Semantic HTML is not a theory,</p>
<p>It’s a map that makes your site usable.</p>
<p>Most teams sprinkle tags like seasoning and call it a day.</p>
<p>Screen readers get lost, search engines guess, and CSS becomes brittle.</p>
<p>I have reviewed a codebase where the markup looked modern and still failed users.</p>
<p>The problem was not divs.</p>
<p>The problem was how the semantic elements were used.</p>
<ol>
<li><code>&lt;main&gt;</code> <strong>— one per page, no nested &lt;main&gt;</strong></li>
</ol>
<p><strong>The mistake:</strong> multiple <code>&lt;main&gt;</code> tags or nesting them inside layout wrappers.<br /><strong>Why it hurts:</strong> screen readers jump straight to <code>&lt;main&gt;</code> to skip Chrome; duplicates destroy that jump.</p>
<p><strong>Use it like this</strong></p>
<pre><code class="lang-typescript">&lt;body&gt;
  &lt;header&gt;…&lt;/header&gt;
  &lt;nav aria-label=<span class="hljs-string">"Primary"</span>&gt;…&lt;/nav&gt;

  &lt;main id=<span class="hljs-string">"content"</span>&gt;
    &lt;!-- The unique primary content <span class="hljs-keyword">of</span> <span class="hljs-built_in">this</span> <span class="hljs-built_in">document</span> --&gt;
  &lt;/main&gt;

  &lt;footer&gt;…&lt;/footer&gt;
&lt;/body&gt;
</code></pre>
<p>Rules that hold up in production:</p>
<ul>
<li><p>Only one <code>&lt;main&gt;</code> per document.</p>
</li>
<li><p>It must not be inside <code>&lt;article&gt;</code>, <code>&lt;aside&gt;</code>, <code>&lt;header&gt;</code>, <code>&lt;footer&gt;</code>, or <code>&lt;section&gt;</code>.</p>
</li>
<li><p>Give it a stable <code>id</code> if you use “Skip to content” links.</p>
</li>
</ul>
<ol start="2">
<li><code>&lt;section&gt;</code> <strong>- only with a heading</strong></li>
</ol>
<p><strong>The mistake:</strong> using <code>&lt;section&gt;</code> as a fancy <code>&lt;div&gt;</code>.<br /><strong>Why it hurts:</strong> sections without headings break the document outline and confuse navigation.</p>
<p><strong>Fix</strong></p>
<pre><code class="lang-typescript">&lt;section aria-labelledby=<span class="hljs-string">"billing-h"</span>&gt;
  &lt;h2 id=<span class="hljs-string">"billing-h"</span>&gt;Billing&lt;/h2&gt;
  &lt;p&gt;Update your payment method.&lt;/p&gt;
&lt;/section&gt;
</code></pre>
<p>If you do not have a natural heading, you probably want a <code>&lt;div&gt;</code>.</p>
<ol start="3">
<li><code>&lt;article&gt;</code> <strong>— self-contained, shareable units</strong></li>
</ol>
<p><strong>The mistake:</strong> wrapping random parts of a page in <code>&lt;article&gt;</code>.<br /><strong>Why it hurts:</strong> <code>&lt;article&gt;</code> tells crawlers and assistive tech that this block could stand alone in a feed or an email.</p>
<p><strong>Use it for things like:</strong></p>
<ul>
<li><p>Blog posts, news items, forum threads</p>
</li>
<li><p>Product reviews, comment cards, changelog entries</p>
</li>
</ul>
<p><strong>Fix</strong></p>
<pre><code class="lang-typescript">&lt;article&gt;
  &lt;header&gt;
    &lt;h1&gt;Release <span class="hljs-number">2.1</span>&lt;/h1&gt;
    &lt;p&gt;Published by Dev Team&lt;/p&gt;
  &lt;/header&gt;

  &lt;p&gt;We added keyboard shortcuts and improved search.&lt;/p&gt;

  &lt;footer&gt;
    &lt;a href=<span class="hljs-string">"#comments"</span>&gt;<span class="hljs-number">12</span> comments&lt;/a&gt;
  &lt;/footer&gt;
&lt;/article&gt;
</code></pre>
<p>If the content makes sense outside this page, <code>&lt;article&gt;</code> is right. If not, prefer <code>&lt;section&gt;</code> or <code>&lt;div&gt;</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758386753031/254dd270-12a3-41ea-95fb-662c98b18f6c.webp" alt class="image--center mx-auto" /></p>
<ol start="4">
<li><code>&lt;header&gt;</code> <strong>— local intros, not only site chrome</strong></li>
</ol>
<p><strong>The mistake:</strong> treating <code>&lt;header&gt;</code> as the global top bar only.<br /><strong>Why it hurts:</strong> you miss useful structure inside articles and sections.</p>
<p>You can place a <code>&lt;header&gt;</code> inside <code>&lt;article&gt;</code> or <code>&lt;section&gt;</code> to group the heading and related intro controls.</p>
<pre><code class="lang-typescript">&lt;article&gt;
  &lt;header&gt;
    &lt;h2&gt;Keyboard Shortcuts&lt;/h2&gt;
    &lt;p&gt;Save minutes every day <span class="hljs-keyword">with</span> these keys.&lt;/p&gt;
  &lt;/header&gt;
  &lt;p&gt;Press “?” to open the cheat sheet.&lt;/p&gt;
&lt;/article&gt;
</code></pre>
<p>Tip: keep only introductory elements in <code>&lt;header&gt;</code>; actions and content belong below.</p>
<ol start="5">
<li><code>&lt;footer&gt;</code> <strong>— closes a scope, not a place for stray links</strong></li>
</ol>
<p><strong>The mistake:</strong> one global footer and nothing else.<br /><strong>Why it hurts:</strong> articles and cards lose a semantic place for metadata and actions.</p>
<p>You can and should use <code>&lt;footer&gt;</code> inside components that read like documents.</p>
<pre><code class="lang-typescript">&lt;article&gt;
  &lt;h2&gt;How We Cache&lt;/h2&gt;
  &lt;p&gt;We use a two-tier strategy <span class="hljs-keyword">with</span> CDN and Redis.&lt;/p&gt;

  &lt;footer&gt;
    &lt;p&gt;Last updated: &lt;time datetime=<span class="hljs-string">"2025-03-19"</span>&gt;March <span class="hljs-number">19</span>, <span class="hljs-number">2025</span>&lt;<span class="hljs-regexp">/time&gt;&lt;/</span>p&gt;
    &lt;a href=<span class="hljs-string">"/caching#discussion"</span>&gt;Join the discussion&lt;/a&gt;
  &lt;/footer&gt;
&lt;/article&gt;
</code></pre>
<p>Keep the global page footer for site-wide navigation and legal links.</p>
<ol start="6">
<li><code>&lt;nav&gt;</code> <strong>— Label it and keep it to navigation</strong></li>
</ol>
<p><strong>The mistake:</strong> wrapping any list of links in <code>&lt;nav&gt;</code>.</p>
<p><strong>Why it hurts:</strong> assistive tech expects navigation landmarks; stuffing random links dilutes signal.</p>
<p>Use <code>&lt;nav&gt;</code> for primary, secondary, breadcrumb, or in-page navigation. Always label it.</p>
<pre><code class="lang-typescript">&lt;nav aria-label=<span class="hljs-string">"Breadcrumb"</span>&gt;
  &lt;ol&gt;
    &lt;li&gt;&lt;a href=<span class="hljs-string">"/"</span>&gt;Home&lt;<span class="hljs-regexp">/a&gt;&lt;/</span>li&gt;
    &lt;li&gt;&lt;a href=<span class="hljs-string">"/docs"</span>&gt;Docs&lt;<span class="hljs-regexp">/a&gt;&lt;/</span>li&gt;
    &lt;li aria-current=<span class="hljs-string">"page"</span>&gt;API&lt;/li&gt;
  &lt;/ol&gt;
&lt;/nav&gt;
</code></pre>
<p>Good patterns:</p>
<ul>
<li><p>Use <code>aria-current="page"</code> or <code>"step"</code> for the active item.</p>
</li>
<li><p>Prefer lists (<code>ul</code>/<code>ol</code>) for grouped nav links.</p>
</li>
</ul>
<ol start="7">
<li><code>&lt;aside&gt;</code> <strong>— relevant but not required</strong></li>
</ol>
<p><strong>The mistake:</strong> using <code>&lt;aside&gt;</code> for main content columns or generic sidebars that hold core tasks.</p>
<p><strong>Why it hurts:</strong> Some users skip asides by default. If it is required to complete the task, it is not an aside.</p>
<p><strong>Right uses</strong></p>
<ul>
<li><p>Tips, callouts, related links</p>
</li>
<li><p>Pull quotes, promo modules, complementary charts</p>
</li>
</ul>
<pre><code class="lang-typescript">&lt;main&gt;
  &lt;article&gt;
    &lt;h1&gt;<span class="hljs-built_in">Set</span> Up Two-Factor Authentication&lt;/h1&gt;
    &lt;p&gt;Open Settings → Security and follow these steps.&lt;/p&gt;
  &lt;/article&gt;

  &lt;aside aria-label=<span class="hljs-string">"Security Tips"</span>&gt;
    &lt;h2&gt;Security Tips&lt;/h2&gt;
    &lt;ul&gt;
      &lt;li&gt;Use a password manager.&lt;/li&gt;
      &lt;li&gt;Store backup codes offline.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/aside&gt;
&lt;/main&gt;
</code></pre>
<h2 id="heading-14-modern-html-javascript-combos-that-feel-like-magic-in-2025">14 Modern HTML + JavaScript Combos That Feel Like Magic in 2025</h2>
<p>HTML and JavaScript keep getting better together. If you’ve been building for the web over the past few years, you know how far the platform has evolved. We’ve reached a point where many features that once required heavy frameworks or third-party libraries now work natively — cleanly, efficiently, and beautifully.</p>
<p>Let’s dive in 👇</p>
<ol>
<li><code>&lt;dialog&gt;</code> <strong>+ JavaScript Modal Controls</strong></li>
</ol>
<p><strong>Why it matters:</strong> The <code>&lt;dialog&gt;</code> element eliminates the need for heavy modal libraries. With native methods like <code>show()</code>, <code>showModal()</code>, and <code>close()</code>, you can manage modals seamlessly.</p>
<pre><code class="lang-typescript">&lt;dialog id=<span class="hljs-string">"myModal"</span>&gt;
  &lt;p&gt;This is a native modal!&lt;/p&gt;
  &lt;button id=<span class="hljs-string">"close"</span>&gt;Close&lt;/button&gt;
&lt;/dialog&gt;

&lt;button id=<span class="hljs-string">"open"</span>&gt;Open Modal&lt;/button&gt;
&lt;script&gt;
<span class="hljs-keyword">const</span> modal = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'myModal'</span>);
<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'open'</span>).onclick = <span class="hljs-function">() =&gt;</span> modal.showModal();
<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'close'</span>).onclick = <span class="hljs-function">() =&gt;</span> modal.close();
&lt;/script&gt;
</code></pre>
<p><strong>Right:</strong> Use <code>&lt;dialog&gt;</code> for lightweight modals.<br /><strong>Wrong:</strong> Building modals from scratch with tons of CSS and JS overhead.</p>
<ol start="2">
<li><code>&lt;details&gt;</code> <strong>+</strong> <code>&lt;summary&gt;</code> <strong>for Expandable Sections</strong></li>
</ol>
<p><strong>Why it matters:</strong> No need for extra JavaScript to create collapsible FAQs or sections.</p>
<pre><code class="lang-typescript">&lt;details&gt;
  &lt;summary&gt;What’s <span class="hljs-keyword">new</span> <span class="hljs-keyword">in</span> HTML5?&lt;/summary&gt;
  &lt;p&gt;Semantic tags, native media, and form enhancements.&lt;/p&gt;
&lt;/details&gt;
</code></pre>
<p><strong>Right:</strong> Let the browser handle expand/collapse logic.<br /><strong>Wrong:</strong> Adding JS just to toggle simple visibility.</p>
<ol start="3">
<li><strong>Intersection Observer + Lazy Loading</strong></li>
</ol>
<p><strong>Why it matters:</strong> You can now control when elements enter the viewport without scroll event listeners.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> images = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">'img[data-src]'</span>);
<span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(<span class="hljs-function"><span class="hljs-params">entries</span> =&gt;</span> {
  entries.forEach(<span class="hljs-function"><span class="hljs-params">entry</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (entry.isIntersecting) {
      entry.target.src = entry.target.dataset.src;
      observer.unobserve(entry.target);
    }
  });
});
images.forEach(<span class="hljs-function"><span class="hljs-params">img</span> =&gt;</span> observer.observe(img));
</code></pre>
<p><strong>Right:</strong> Use Intersection Observer for lazy loading or animations.<br /><strong>Wrong:</strong> Using scroll handlers that trigger on every pixel move.</p>
<ol start="4">
<li><code>&lt;template&gt;</code> <strong>+ Cloning Elements</strong></li>
</ol>
<p><strong>Why it matters:</strong> It’s perfect for rendering repetitive content like lists or cards.</p>
<pre><code class="lang-typescript">&lt;template id=<span class="hljs-string">"card"</span>&gt;
  &lt;div <span class="hljs-keyword">class</span>=<span class="hljs-string">"card"</span>&gt;
    &lt;h3&gt;&lt;/h3&gt;
    &lt;p&gt;&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;div id=<span class="hljs-string">"container"</span>&gt;&lt;/div&gt;
&lt;script&gt;
<span class="hljs-keyword">const</span> template = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'card'</span>);
<span class="hljs-keyword">const</span> container = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'container'</span>);
[<span class="hljs-string">'HTML'</span>, <span class="hljs-string">'CSS'</span>, <span class="hljs-string">'JS'</span>].forEach(<span class="hljs-function"><span class="hljs-params">topic</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> clone = template.content.cloneNode(<span class="hljs-literal">true</span>);
  clone.querySelector(<span class="hljs-string">'h3'</span>).textContent = topic;
  clone.querySelector(<span class="hljs-string">'p'</span>).textContent = <span class="hljs-string">'Learn '</span> + topic;
  container.appendChild(clone);
});
&lt;/script&gt;
</code></pre>
<p><strong>Right:</strong> Reuse templates for dynamic content.<br /><strong>Wrong:</strong> Creating repetitive markup manually with <code>innerHTML</code>.</p>
<ol start="5">
<li><code>&lt;input type="color"&gt;</code> <strong>+ JS Customization</strong></li>
</ol>
<p><strong>Why it matters:</strong> It gives users a native color picker without dependencies.</p>
<pre><code class="lang-typescript">&lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"color"</span> id=<span class="hljs-string">"picker"</span>&gt;
&lt;div id=<span class="hljs-string">"preview"</span>&gt;Preview Text&lt;/div&gt;

&lt;script&gt;
<span class="hljs-keyword">const</span> picker = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'picker'</span>);
<span class="hljs-keyword">const</span> preview = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'preview'</span>);
picker.oninput = <span class="hljs-function">() =&gt;</span> preview.style.color = picker.value;
&lt;/script&gt;
</code></pre>
<p><strong>Right:</strong> Enhance native elements with JS.<br /><strong>Wrong:</strong> Using third-party color picker plugins for basic use cases.</p>
<ol start="6">
<li><strong>Clipboard API + Buttons</strong></li>
</ol>
<p><strong>Why it matters:</strong> Copy-to-clipboard is now natively supported.</p>
<pre><code class="lang-typescript">&lt;button id=<span class="hljs-string">"copy"</span>&gt;Copy&lt;/button&gt;
&lt;p id=<span class="hljs-string">"text"</span>&gt;Copy <span class="hljs-built_in">this</span> text!&lt;/p&gt;

&lt;script&gt;
copy.onclick = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> navigator.clipboard.writeText(text.textContent);
  alert(<span class="hljs-string">'Copied!'</span>);
};
&lt;/script&gt;
</code></pre>
<p><strong>Right:</strong> Use <code>navigator.clipboard</code> for simple copy features.<br /><strong>Wrong:</strong> Using hidden textareas or execCommand hacks.</p>
<ol start="7">
<li><code>fetch()</code> <strong>+</strong> <code>async/await</code></li>
</ol>
<p><strong>Why it matters:</strong> Simplifies API requests without heavy libraries like Axios.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUser</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/users/1'</span>);
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> res.json();
  <span class="hljs-built_in">console</span>.log(user);
}
getUser();
</code></pre>
<p><strong>Right:</strong> Use async/await for clean, readable async code.<br /><strong>Wrong:</strong> Callback hell or unnecessary dependencies.</p>
<ol start="8">
<li><code>&lt;progress&gt;</code> <strong>+ JS Updates</strong></li>
</ol>
<p><strong>Why it matters:</strong> Native progress bars are accessible and easy to update dynamically.</p>
<pre><code class="lang-typescript">&lt;progress id=<span class="hljs-string">"bar"</span> value=<span class="hljs-string">"0"</span> max=<span class="hljs-string">"100"</span>&gt;&lt;/progress&gt;

&lt;script&gt;
<span class="hljs-keyword">let</span> value = <span class="hljs-number">0</span>;
<span class="hljs-keyword">const</span> bar = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'bar'</span>);
<span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
  value = (value + <span class="hljs-number">10</span>) % <span class="hljs-number">110</span>;
  bar.value = value;
}, <span class="hljs-number">1000</span>);
&lt;/script&gt;
</code></pre>
<p><strong>Right:</strong> Use <code>&lt;progress&gt;</code> for native UI.<br /><strong>Wrong:</strong> Using divs with CSS for progress when native exists.</p>
<ol start="9">
<li><code>localStorage</code> <strong>+ JSON Handling</strong></li>
</ol>
<p><strong>Why it matters:</strong> Perfect for persisting user preferences without backend calls.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> user = { theme: <span class="hljs-string">'dark'</span>, fontSize: <span class="hljs-number">16</span> };
<span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'user'</span>, <span class="hljs-built_in">JSON</span>.stringify(user));
<span class="hljs-keyword">const</span> saved = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'user'</span>));
</code></pre>
<p><strong>Right:</strong> Store structured data as JSON.<br /><strong>Wrong:</strong> Storing plain strings without structure.</p>
<ol start="10">
<li><code>&lt;video&gt;</code> <strong>+ JS Controls</strong></li>
</ol>
<p><strong>Why it matters:</strong> The native video API lets you control playback without external players.</p>
<pre><code class="lang-typescript">&lt;video id=<span class="hljs-string">"vid"</span> width=<span class="hljs-string">"320"</span> controls&gt;
  &lt;source src=<span class="hljs-string">"video.mp4"</span> <span class="hljs-keyword">type</span>=<span class="hljs-string">"video/mp4"</span>&gt;
&lt;/video&gt;
&lt;button onclick=<span class="hljs-string">"vid.play()"</span>&gt;Play&lt;/button&gt;
&lt;button onclick=<span class="hljs-string">"vid.pause()"</span>&gt;Pause&lt;/button&gt;
</code></pre>
<p><strong>Right:</strong> Use native controls for performance and accessibility.<br /><strong>Wrong:</strong> Using bloated video plugins for simple playback.</p>
<ol start="11">
<li><code>&lt;canvas&gt;</code> <strong>+ JS Drawing</strong></li>
</ol>
<p><strong>Why it matters:</strong> Perfect for visualizations or custom animations.</p>
<pre><code class="lang-typescript">&lt;canvas id=<span class="hljs-string">"art"</span> width=<span class="hljs-string">"200"</span> height=<span class="hljs-string">"200"</span>&gt;&lt;/canvas&gt;
&lt;script&gt;
<span class="hljs-keyword">const</span> ctx = art.getContext(<span class="hljs-string">'2d'</span>);
ctx.fillStyle = <span class="hljs-string">'orange'</span>;
ctx.fillRect(<span class="hljs-number">20</span>, <span class="hljs-number">20</span>, <span class="hljs-number">150</span>, <span class="hljs-number">100</span>);
&lt;/script&gt;
</code></pre>
<p><strong>Right:</strong> Use canvas for dynamic graphics.<br /><strong>Wrong:</strong> Using DOM elements for visual-heavy tasks.</p>
<ol start="12">
<li><code>&lt;meter&gt;</code> <strong>+ Live Stats</strong></li>
</ol>
<p><strong>Why it matters:</strong> Displays real-time data like scores or battery.</p>
<pre><code class="lang-typescript">&lt;meter id=<span class="hljs-string">"score"</span> min=<span class="hljs-string">"0"</span> max=<span class="hljs-string">"100"</span> value=<span class="hljs-string">"45"</span>&gt;&lt;/meter&gt;
&lt;script&gt;
<span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> score.value = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random()*<span class="hljs-number">100</span>), <span class="hljs-number">1000</span>);
&lt;/script&gt;
</code></pre>
<p><strong>Right:</strong> Use <code>&lt;meter&gt;</code> for measurable quantities.<br /><strong>Wrong:</strong> Styling <code>&lt;div&gt;</code>s to fake meters.</p>
<ol start="13">
<li><strong>CSS Variables + JS Interaction</strong></li>
</ol>
<p><strong>Why it matters:</strong> JS can manipulate CSS variables live, improving theme switching.</p>
<pre><code class="lang-typescript">&lt;style&gt;
  :root { --bg: #fff; }
  body { background: <span class="hljs-keyword">var</span>(--bg); }
&lt;/style&gt;
&lt;button id=<span class="hljs-string">"dark"</span>&gt;Dark Mode&lt;/button&gt;

&lt;script&gt;
dark.onclick = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">document</span>.documentElement.style.setProperty(<span class="hljs-string">'--bg'</span>, <span class="hljs-string">'#222'</span>);
};
&lt;/script&gt;
</code></pre>
<p><strong>Right:</strong> Use CSS vars for dynamic theming.<br /><strong>Wrong:</strong> Overwriting inline styles repeatedly.</p>
<ol start="14">
<li><strong>Web Share API + Buttons</strong></li>
</ol>
<p><strong>Why it matters:</strong> Share links natively from web apps.</p>
<pre><code class="lang-typescript">&lt;button id=<span class="hljs-string">"share"</span>&gt;Share This Page&lt;/button&gt;
&lt;script&gt;
share.onclick = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> navigator.share({ title: <span class="hljs-string">'Frontend Magic'</span>, url: location.href });
};
&lt;/script&gt;
</code></pre>
<p><strong>Right:</strong> Use native sharing for mobile-first UX.<br /><strong>Wrong:</strong> Forcing users to copy URLs manually.</p>
<h1 id="heading-final-thoughts"><strong>Final thoughts</strong></h1>
<p>If this article was helpful and surprised you with the power that HTML truly has, let me know in the comments.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://levelup.gitconnected.com/top-5-html-features-youre-not-using-but-should-be-73f8544c2116">https://levelup.gitconnected.com/top-5-html-features-youre-not-using-but-should-be-73f8544c2116</a></p>
<p><a target="_blank" href="https://dev.to/devshefali/21-html-tips-you-must-know-about-55j7?context=digest">https://dev.to/devshefali/21-html-tips-you-must-know-about-55j7?context=digest</a></p>
<p><a target="_blank" href="https://dev.to/ayabouchiha/5-html-tags-that-almost-nobody-knows-5p5">https://dev.to/ayabouchiha/5-html-tags-that-almost-nobody-knows-5p5</a></p>
<p><a target="_blank" href="https://halimshams.medium.com/the-hidden-html-tags-you-should-be-using-21c413a8fb3a">https://halimshams.medium.com/the-hidden-html-tags-you-should-be-using-21c413a8fb3a</a></p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/less-common-html-tags/?ref=dailydev">https://www.freecodecamp.org/news/less-common-html-tags/?ref=dailydev</a></p>
<p><a target="_blank" href="https://medium.com/coding-beauty/rare-html-tags-9ed55211acd5">https://medium.com/coding-beauty/rare-html-tags-9ed55211acd5</a></p>
<p><a target="_blank" href="https://medium.com/developers-corner/5-html-tips-probably-you-dont-know-3dc68d9b5214">https://medium.com/developers-corner/5-html-tips-probably-you-dont-know-3dc68d9b5214</a></p>
<p><a target="_blank" href="https://dev.to/ashishxcode/5-powerful-html-attributes-that-dont-require-javascript-lfb?ref=dailydev">https://dev.to/ashishxcode/5-powerful-html-attributes-that-dont-require-javascript-lfb?ref=dailydev</a></p>
<p><a target="_blank" href="https://medium.com/web-tech-journals/semantic-html-isnt-just-for-screen-readers-it-s-a-superpower-you-re-probably-ignoring-387af47d6fd8">https://medium.com/web-tech-journals/semantic-html-isnt-just-for-screen-readers-it-s-a-superpower-you-re-probably-ignoring-387af47d6fd8</a></p>
<p><a target="_blank" href="https://medium.com/@sonampatel_97163/html5-semantic-tags-7-elements-youre-probably-using-wrong-397430906fac">https://medium.com/@sonampatel_97163/html5-semantic-tags-7-elements-youre-probably-using-wrong-397430906fac</a></p>
<p><a target="_blank" href="https://pixicstudio.medium.com/99-of-developers-dont-know-these-aria-attributes-exist-8bbc57647818">https://pixicstudio.medium.com/99-of-developers-dont-know-these-aria-attributes-exist-8bbc57647818</a></p>
<p><a target="_blank" href="http://medium.com/@theabhishek.040/modern-html-javascript-combos-2025-34686591563a">http://medium.com/@theabhishek.040/modern-html-javascript-combos-2025-34686591563a</a></p>
<p><a target="_blank" href="https://habtesoft.medium.com/metadata-and-meta-tags-the-unsung-heroes-of-the-web-80b1e17e2ccb">https://habtesoft.medium.com/metadata-and-meta-tags-the-unsung-heroes-of-the-web-80b1e17e2ccb</a></p>
<p><a target="_blank" href="https://medium.com/@TusharKanjariya/the-html-tricks-i-learned-the-hard-way-2194edcbc9b2">https://medium.com/@TusharKanjariya/the-html-tricks-i-learned-the-hard-way-2194edcbc9b2</a></p>
]]></content:encoded></item><item><title><![CDATA[🔥 My NextJS Handbook]]></title><description><![CDATA[Next.js is a React-based framework that allows you to build server-side-rendered applications with ease. With Next.js, you can create dynamic and fast-loading web pages that are optimized for search engines and social media platforms. Some of the key...]]></description><link>https://blog.tuanhadev.tech/mastering-nextjs</link><guid isPermaLink="true">https://blog.tuanhadev.tech/mastering-nextjs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><category><![CDATA[Server side rendering]]></category><category><![CDATA[static site generation]]></category><category><![CDATA[SEO]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Wed, 08 Jan 2025 12:38:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Sc5RKXLBjGg/upload/dc79416ab38a259bc81476ff18a94072.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Next.js is a React-based framework that allows you to build server-side-rendered applications with ease. With Next.js, you can create dynamic and fast-loading web pages that are optimized for search engines and social media platforms. Some of the key benefits of using Next.js include:</p>
<ul>
<li><p>Automatic code splitting for faster page loads.</p>
</li>
<li><p>Server-side rendering for improved SEO and performance.</p>
</li>
<li><p>Built-in support for CSS modules and styled components.</p>
</li>
<li><p>Easy deployment with Vercel, the platform that was built specifically for Next.js.</p>
</li>
</ul>
<p>Today, I’m going to explain some advanced concepts of Next.js that most developers don’t know. You can use them to optimize your App and improve the Developer experience.</p>
<h2 id="heading-understanding-nextjs-rendering-strategies-ssg-csg-ssg-and-isr">Understanding Next.js Rendering Strategies — SSG, CSG, SSG, and ISR</h2>
<p>Sources: <a target="_blank" href="https://www.patterns.dev/react/react-server-components/">https://www.patterns.dev/react/</a></p>
<p>One of the advantages of using Next.js is the versatility in regard to how it builds the page on the user’s browser. If you can comprehend how these strategies work, you will have an easier time building a faster and more efficient site.</p>
<p>Next.js has four rendering strategies:</p>
<ul>
<li><p><strong>Server-Side Rendering (SSR)</strong></p>
</li>
<li><p><strong>Client-Side Rendering (CSR)</strong></p>
</li>
<li><p><strong>Static-Site Generation (SSG)</strong></p>
</li>
<li><p><strong>Incremental-Statis Regeneration (ISR)</strong></p>
</li>
<li><p><strong>React Server Components (RSCs)</strong></p>
</li>
</ul>
<p>I will explain each strategy, including the process behind the scenes, these use cases, and the pros and cons.</p>
<h3 id="heading-server-side-rendering">Server-side Rendering</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734439816499/849a4843-d7c2-45f9-8c1a-d22356b72ab8.webp" alt class="image--center mx-auto" /></p>
<p>Server-side rendering (SSR) is one of the oldest methods of rendering web content. SSR generates the full HTML for the page content to be rendered in response to a user request. The content may include data from a datastore or external API.</p>
<p>The connect and fetch operations are handled on the server. HTML required to format the content is also generated on the server. Thus, with SSR, we can avoid making additional round-trip requests for data fetching and templating. As such, rendering code is not required on the client, and the JavaScript corresponding to this need not be sent to the client.</p>
<p>With SSR, every request is treated independently and will be processed as a new request by the server. Even if the output of two consecutive requests is not very different, the server will process and generate it from scratch. Since the server is common to multiple users, the processing capability is shared by all active users at a given time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768472060295/a24754fe-82a0-4877-826e-3d0719f77fd7.webp" alt class="image--center mx-auto" /></p>
<p><strong>Pros and Cons</strong></p>
<p>Executing the rendering code on the server and reducing JavaScript offers the following advantages.</p>
<ul>
<li><p><strong>Lesser JavaScript leads to quicker FCP and TTI:</strong> In cases where there are multiple UI elements and application logic on the page, SSR has considerably less JavaScript when compared to CSR. The time required to load and process the script is thus lesser. FP, FCP and TTI are shorter and FCP = TTI. With SSR, users will not be left waiting for all the screen elements to appear and for it to become interactive.</p>
</li>
<li><p><strong>Provides additional budget for client-side JavaScript:</strong> Development teams are required to work with a JS budget that limits the amount of JS on the page to achieve the desired performance. With SSR, since you are directly eliminating the JS required to render the page, it creates additional space for any third party JS that may be required by the application.</p>
</li>
<li><p><strong>SEO enabled:</strong> Since all processing takes place on the server, the response from the server may be delayed in case of one or more of the following scenarios(Multiple simultaneous users causing excess load on the server, Server code not optimized)</p>
</li>
<li><p><strong>Full page reloads required for some interactions:</strong> Since all code is not available on the client, frequent round trips to the server are required for all key operations causing full page reloads. This could increase the time between interactions as users are required to wait longer between operations. A single-page application is thus not possible with SSR.</p>
</li>
</ul>
<h3 id="heading-client-side-rendering">Client-side Rendering</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734440288983/b3f84567-0b85-4fde-9b87-7aada9de4ebb.webp" alt class="image--center mx-auto" /></p>
<p>In Client-Side Rendering (CSR) only the barebones HTML container for a page is rendered by the server. The logic, data fetching, templating, and routing required to display content on the page is handled by JavaScript code that executes in the browser/client. CSR became popular as a method of building single-page applications. It helped to blur the difference between websites and installed applications.</p>
<p>As the complexity of the page increases to show images, display data from a data store and include event handling, the complexity and size of the JavaScript code required to render the page will also increase. CSR resulted in large JavaScript bundles, which increased the FCP and TTI of the page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768471873756/4567aa95-9990-4955-bb95-3803d96c8cca.webp" alt class="image--center mx-auto" /></p>
<p>As shown in the above illustration, as the size of bundle.js increases, the FCP and TTI are pushed forward. This implies that the user will see a blank screen for the entire duration between FP and FCP.</p>
<p><strong>Pros and Cons</strong></p>
<p>With React most of the application logic is executed on the client and it interacts with the server through API calls to fetch or save data. Almost all of the UI is thus generated on the client. The entire web application is loaded on the first request. As the user navigates by clicking on links, no new request is generated to the server for rendering the pages. The code runs on the client to change the view/data.</p>
<p>CSR allows us to have a Single-Page Application that supports navigation without page refresh and provides a great user experience. As the data processed to change the view is limited, routing between pages is generally faster making the CSR application seem more responsive. CSR also allows developers to achieve a clear separation between client and server code.</p>
<p>Despite the great interactive experience that it provides, there are a few pitfalls to this CSR.</p>
<ol>
<li><p><strong>SEO considerations:</strong> Most web crawlers can interpret server rendered websites in a straight-forward manner. Things get slightly complicated in the case of client-side rendering as large payloads and a waterfall of network requests (e.g for API responses) may result in meaningful content not being rendered fast enough for a crawler to index it. Crawlers may understand JavaScript but there are limitations. As such, some workarounds are required to make a client-rendered website SEO friendly.</p>
</li>
<li><p><strong>Performance</strong>: With client-side rendering, the response time during interactions is greatly improved as there is no round trip to the server. However, for browsers to render content on client-side the first time, they have to wait for the JavaScript to load first and start processing. Thus users will experience some lag before the initial page loads. This may affect the user experience as the size of JS bundles get bigger and/or the client does not have sufficient processing power.</p>
</li>
<li><p><strong>Code Maintainability:</strong> Some elements of code may get repeated across client and server (APIs) in different languages. In other cases, clean separation of business logic may not be possible. Examples of this could include validations and formatting logic for currency and date fields.</p>
</li>
<li><p><strong>Data Fetching</strong>: With client-side rendering, data fetching is usually event-driven. The page could initially be loaded without any data. Data may be subsequently fetched on the occurrence of events like page-load or button-clicks using API calls. Depending on the size of data this could add to the load/interaction time of the application.</p>
</li>
</ol>
<p>The importance of these considerations may be different across applications. Developers are often interested in finding SEO friendly solutions that can serve pages faster without compromising on the interaction time. Priorities assigned to the different performance criteria may be different based on application requirements. Sometimes it may be enough to use client- side rendering with some tweaks instead of going for a completely different pattern.</p>
<p>Relevant resources: <a target="_blank" href="https://www.yegor256.com/2026/01/25/spa-vs-performance.html?ref=dailydev">SPAs Are a Performance Dead End</a></p>
<h3 id="heading-static-site-generation-ssg">Static-Site Generation (SSG)</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734441254153/659a094c-16e1-48ae-a54a-1d2c08940bb2.webp" alt class="image--center mx-auto" /></p>
<p>Based on our discussion on SSR, we know that a high request processing time on the server negatively affects the TTFB. Similarly, with CSR, a large JavaScript bundle can be detrimental to the FCP, LCP and TTI of the application due to the time taken to download and process the script.</p>
<p>Static rendering or static generation (SSG) attempts to resolve these issues by delivering pre-rendered HTML content to the client that was generated when the site was built.</p>
<p>A static HTML file is generated ahead of time corresponding to each route that the user can access. These static HTML files may be available on a server or a CDN and fetched as and when requested by the client.</p>
<p>Static files may also be cached thereby providing greater resiliency. Since the HTML response is generated in advance, the processing time on the server is negligible thereby resulting in a faster TTFB and better performance. In an ideal scenario, client-side JS should be minimal and static pages should become interactive soon after the response is received by the client. As a result, SSG helps to achieve a faster FCP/TTI.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768472238178/b6436591-530b-444a-8370-8c9e08fd9999.webp" alt class="image--center mx-auto" /></p>
<p><strong>SSG - Key Considerations</strong></p>
<ol>
<li><p><strong>A large number of HTML files:</strong> Individual HTML files need to be generated for every possible route that the user may access. For example, when using it for a blog, an HTML file will be generated for every blog post available in the data store. Subsequently, edits to any of the posts will require a rebuild for the update to be reflected in the static HTML files. Maintaining a large number of HTML files can be challenging.</p>
</li>
<li><p><strong>Hosting Dependency:</strong> For an SSG site to be super-fast and respond quickly, the hosting platform used to store and serve the HTML files should also be good. Superlative performance is possible if a well-tuned SSG website is hosted right on multiple CDNs to take advantage of edge-caching.</p>
</li>
<li><p><strong>Dynamic Content:</strong> An SSG site needs to be built and re-deployed every time the content changes. The content displayed may be stale if the site has not been built + deployed after any content change. This makes SSG unsuitable for highly dynamic content.</p>
</li>
</ol>
<h3 id="heading-incremental-static-regeneration-isr">Incremental Static Regeneration (ISR)</h3>
<p>Static Generation (SSG) addresses most of the concerns of SSR and CSR but is suitable for rendering mostly static content. It poses limitations when the content to be rendered is dynamic or changing frequently.</p>
<p>Think of a growing blog with multiple posts. You wouldn’t possibly want to rebuild and redeploy the site just because you want to correct a typo in one of the posts. Similarly, one new blog post should also not require a rebuild for all the existing pages. Thus, SSG on its own is not enough for rendering large websites or applications.</p>
<p>The Incremental Static Generation (iSSG) pattern was introduced as an upgrade to SSG, to help solve the dynamic data problem and help static sites scale for large amounts of frequently changing data. iSSG allows you to update existing pages and add new ones by pre-rendering a subset of pages in the background even while fresh requests for pages are coming in.</p>
<p>iSSG works on two fronts to incrementally introduce updates to an existing static site after it has been built.</p>
<ul>
<li><p><strong>Adding New Pages</strong>: The lazy loading concept is used to include new pages on the website after the build. This means that the new page is generated immediately on the first request. While the generation takes place, a fallback page or a loading indicator can be shown to the user on the front-end. Compare this to the SSG scenario discussed earlier for individual details page per product. The 404 error page was shown here as a fallback for non-existent pages. With fallback: true, if the page corresponding to a specific product is unavailable, we show a fallback version of the page, eg., a loading indicator as shown in the Product function above. Meanwhile, Next.js will generate the page in the background. Once it is generated, it will be cached and shown instead of the fallback page. The cached version of the page will now be shown to any subsequent visitors immediately upon request. For both new and existing pages, we can set an expiration time for when Next.js should revalidate and update it. This can be achieved by using the revalidate property as shown in the following section. In ISR, <code>fallback: false</code> returns 404 for unknown pages.<br />  <code>fallback: true</code> shows a loading state while the page is generated.<br />  <code>fallback: 'blocking'</code> waits for the page to be generated and then returns the full HTML without a loading state.</p>
</li>
<li><p><strong>Update Existing pages:</strong> To re-render an existing page, a suitable timeout is defined for the page. This will ensure that the page is revalidated whenever the defined timeout period has elapsed. The timeout could be set to as low as 1 second. The user will continue to see the previous version of the page, till the page has finished revalidation. Thus, iSSG uses the <a target="_blank" href="https://web.dev/stale-while-revalidate/">stale-while-revalidate</a> strategy where the user receives the cached or stale version while the revalidation takes place. The revalidation takes place completely in the background without the need for a full rebuild.</p>
</li>
</ul>
<h3 id="heading-react-server-components">React Server Components</h3>
<p><a target="_blank" href="https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html">React’s Server Components</a> enable <strong>modern UX with a server-driven mental model</strong>. This is quite different from Server-side Rendering (SSR) of components and results in significantly <a target="_blank" href="https://twitter.com/sophiebits/status/1341098388062756867">smaller</a> client-side JavaScript bundles</p>
<blockquote>
<p><strong><em>Update (React 18+ / Next.js 13+): React Server Components are now a production reality in Next.js 13+ with the App Router. Unlike classic SSR, RSCs allow you to render part of your UI on the server ahead of time without sending the associated JS to the client—dramatically shrinking client bundles (early reports show 20%+ reductions). The Container/Presentational pattern is a great candidate for RSC: the “container” (data-fetching logic) can be a Server Component that fetches data and passes it as props to a presentational Client Component, meaning the fetching logic never ships to the browser.</em></strong></p>
<p><strong><em>In Next.js App Router, you no longer use</em></strong> <code>getServerSideProps</code>—instead, any React component in the <code>app/</code> directory can be async to fetch data on the server. React Server Components are <em>not</em> a replacement for SSR—they complement it. You typically use RSC for the majority of the page (rendered and streamed as part of SSR), and add <code>'use client'</code> directives for components that need interactivity.</p>
<p><strong><em>Server Actions (stabilizing in React 19/20) allow you to define form or event handlers on the server using</em></strong> <code>'use server'</code> directive and call them from client components, further blurring the line between client and server.</p>
</blockquote>
<p>React’s new Server Components compliment Server-side rendering, enabling rendering into an intermediate abstraction format without needing to add to the JavaScript bundle. This both allows merging the server-tree with the client-side tree without a loss of state and enables scaling up to more components.</p>
<p>Server Components are not a replacement for SSR. When paired together, they support quickly rendering in an intermediate format, then having Server-side rendering infrastructure rendering this into HTML enabling early paints to still be fast. We SSR the Client components which the Server components emit, similar to how SSR is used with other data-fetching mechanisms.</p>
<p>This time however, the JavaScript bundle will be significantly smaller. Early explorations have shown that bundle size wins could be significant (-18-29%), but the React team will have a clearer idea of wins in the wild once further infrastructure work is complete.</p>
<blockquote>
<p><strong><em>[RFC]: If we migrate the above example to a Server Component we can use the exact same code for our feature but avoid sending it to the client - a code savings of over 240K (uncompressed):</em></strong></p>
</blockquote>
<p><strong>Will Server Components replace Next.js SSR?</strong></p>
<p>No. They are quite different. Initial adoption of Server Components will actually be experimented with via meta-frameworks such as Next.js as research and experimentation continue.</p>
<p>To summarize, a <a target="_blank" href="https://news.ycombinator.com/item?id=25499171">good explanation</a> of the differences between Next.js SSR and Server Components from Dan Abramov:</p>
<ul>
<li><p><strong>Code for Server Components is never delivered to the client.</strong> In many implementations of SSR using React, component code gets sent to the client via JavaScript bundles anyway. This can delay interactivity.</p>
</li>
<li><p><strong>Server components enable access to the back-end from anywhere in the tree.</strong> When using Next.js, you’re used to accessing the back-end via getServerProps() which has the limitation of only working at the top-level page. Random npm components are unable to do this.</p>
</li>
<li><p><strong>Server Components may be refetched while maintaining Client-side state inside of the tree.</strong> This is because the main transport mechanism is much richer than just HTML, allowing the refetching of a server-rendered part (e.g such as a search result list) without blowing away state inside (e.g search input text, focus, text selection)</p>
</li>
</ul>
<h2 id="heading-nextjs-server-actions-lessons-learned">Next.js Server Actions Lessons Learned</h2>
<p>I have been building web apps for years, and one thing that has always been a pain is managing that messy back-and-forth between the client and the server. Next.js made things easier, especially with server-side rendering, but it still felt like there was a missing piece. Then came Server Actions, when I first heard about them, I was skeptical — “Server code directly in React components? Sounds like a recipe for disaster“. But after using them for a few projects, I’m a convert. This section is my brain dumb on Server Actions — how they work, what they matter, and when they can be useful (and when they might be trouble than they are worth).</p>
<h3 id="heading-what-are-the-nextjs-server-actions">What are the Next.js Server Actions?</h3>
<p>So, what exactly are these Server Actions? Basically, they are the way to write server-side code — the stuff that is used to live in separate API routes — right inside your React components. Instead of creating a separate file for server interactions or business logic, you can now directly put that logic where they are being used.</p>
<p>The secret sauce is the “use server“ directive. Think of it as a tag that tells Next.js, “run this code on the server“. You can tag the entire file or just specific functions. Here’s a quick example.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions.ts</span>
<span class="hljs-string">"use server"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addItemToCart</span>(<span class="hljs-params">itemId: <span class="hljs-built_in">string</span>, quantity: <span class="hljs-built_in">number</span></span>) </span>{
  <span class="hljs-comment">// This runs on the server</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Adding <span class="hljs-subst">${quantity}</span> of item <span class="hljs-subst">${itemId}</span> to the cart...`</span>);
}
</code></pre>
<p>Now, if you’ve used Next.js before, you might be thinking, “Wait, isn’t that what API routes are for?” And yes, API routes have been the traditional way to handle server stuff. But Server Actions are different. They are more tightly integrated with your components. Instead of separate files and a bunch of fetch calls, you can have the logic right there, next to your UI.</p>
<p>Of course, Server Actions aren’t meant to replace API routes entirely. If you are building an public API or need to talk to the external services, API Routes are still a way to go. But for those common tasks that are deeply tied to your UI, especially data mutations, Server Actions can be a game-changer. They are like specialized tools in your toolbox, not a replacement for the whole toolbox.</p>
<h3 id="heading-how-does-nextjs-server-actions-work-under-the-hood">How does Next.js Server Actions Work Under The Hood</h3>
<p>Understanding the underlying mechanisms is the key to using them effectively, and, of course, debugging them when things go wrong.</p>
<p>First up, that <code>"use server"</code> directive. As we touched upon, it’s your way of telling Next.js what code should run on the server. You can either put it at the top of the file, which makes every exported function in that file a Server Action, or you can add it to individual functions. Generally, it's cleaner to keep Server Actions in dedicated files. It makes things more organized. Here is an example of a file with multiple Server Actions:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions/products.ts</span>

<span class="hljs-string">"use server"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addProduct</span>(<span class="hljs-params">data: ProductData</span>) </span>{
  <span class="hljs-comment">// ... runs on the server</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteProduct</span>(<span class="hljs-params">productId: <span class="hljs-built_in">string</span></span>) </span>{
  <span class="hljs-comment">// ... also runs on the server</span>
}
</code></pre>
<p>Now, when you call a Server Action from a client component, it’s not just a regular function call. Next.js does some magic behind the scenes — it’s like an RPC (Remote Procedure Call) process. Here’s the breakdown: your client code calls the Server Action function. Next.js then serializes the arguments you passed — basically, converting them into a format that can be sent over the network. Then, a <code>POST</code> request is fired off to a special Next.js endpoint, with the serialized data and some extra info to identify the Server Action. The server receives the request, figures out which Server Action to run, deserializes arguments, and executes the code. The server then serializes the returned value and sends it back to the client. The client receives the response, deserializes it, and — this is the cool part — automatically re-renders the relevant parts of your UI.</p>
<p>The serialization part is where things get interesting. We’re not just dealing with simple strings and numbers here. What if you need to pass a <code>Date</code> object or a <code>Map</code>? Next.js handles the serialization and deserialization. Here is an example to demonstrate that:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions/data.ts</span>
<span class="hljs-string">"use server"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processData</span>(<span class="hljs-params">date: <span class="hljs-built_in">Date</span>, data: <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt;</span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Date:"</span>, date); <span class="hljs-comment">// Correctly receives the Date object</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Data:"</span>, data); <span class="hljs-comment">// Correctly receives the Map object</span>
  <span class="hljs-keyword">return</span> { updated: <span class="hljs-literal">true</span> };
}
</code></pre>
<p>Server Actions are tightly integrated with React’s rendering. For instance, you can hook a Server Action directly to a form submission using the <code>action</code> attribute. Next.js handles all the messy details for you. Like this:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/components/MyForm.tsx</span>
<span class="hljs-string">"use client"</span>

<span class="hljs-keyword">import</span> { myServerAction } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/app/actions'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;form action={myServerAction}&gt;
      {<span class="hljs-comment">/* Form fields */</span>}
      &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
  );
}
</code></pre>
<p>Or, if you want more control, just call the Server Action from an event handler:</p>
<pre><code class="lang-typescript"><span class="hljs-string">"use client"</span>

<span class="hljs-keyword">import</span> { myServerAction } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/app/actions'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-keyword">async</span>() =&gt; {
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> myServerAction();
    <span class="hljs-comment">// Handle the result</span>
  }

  <span class="hljs-keyword">return</span> &lt;button onClick={handleClick}&gt;Click Me&lt;/button&gt;
}
</code></pre>
<p>Anh, the best part? After the Server Action completes, Next.js automatically re-renders the parts of your UI that might have changed because of it. No more manually fetching data or updating the state after a mutation. It just works if the user doesn’t have JavaScript enabled or if it’s still loading; forms with Server Actions will work as regular HTML forms. Once JS is available, it will be enhanced by Next.js.</p>
<p>Here’s a diagram to visualize the process:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1751369415685/5238e952-ad75-45ba-beaf-c7fd28704b4f.webp" alt class="image--center mx-auto" /></p>
<p>Now, Server Actions aren’t a magic bullet, and I’ve run into a few gotchas, which we’ll get to later. But they do streamline a lot of the tedious work involved in client-server communication.</p>
<h3 id="heading-why-do-server-actions-matter-in-the-current-landscape">Why Do Server Actions Matter in the Current Landscape?</h3>
<p>Let’s be real, the world of web development is constantly throwing new things at us. So, why should we care about Server Actions? Here’s the deal: building modern web apps is complicated. We want these rich, interactive experiences, but managing the communication between the client and server can be a real pain. We often end up spending more time on the plumbing — API routes, data fetching, state management — than on the actual features users care about.</p>
<p>Server Actions tackle this problem head-on. By letting us put server-side code right in our React components, they drastically simplify things. Think about it: no more separate API route files, no more manually fetching data after a mutation. Your code becomes more concise and easier to follow, especially for smaller teams or solo developers. I’ve found that on smaller projects, Server Actions have cut down development time significantly.</p>
<p>And it’s not just about convenience. Server Actions can also boost performance. By reducing those back-and-forth trips between the client and server, especially for things like updating data, we can make our apps feel snappier. Fewer network requests mean faster loading times, and that’s a win for user experience. Plus, they play nicely with Next.js’s caching features, so you can optimize things even further.</p>
<p>Security is another big win. With Server Actions, sensitive operations — database queries, API calls with secret keys, etc. — stay on the server. That’s a huge relief in today’s world of increasing security threats. Also, they are always invoked with <code>POST</code> request.</p>
<p>Server Actions are also part of a bigger trend. Full-stack frameworks like Next.js are blurring the lines between frontend and backend. Server Actions are a natural step in that direction, letting developers handle more of the application lifecycle without needing to be a backend guru. This doesn’t mean specialized roles are going away, but it does mean that full-stack developers can be more efficient and productive.</p>
<p>Now, I’m not saying Server Actions are perfect or that they should replace every other way of doing things. But they do offer a powerful new approach, especially for data-heavy applications. They’re a significant step forward for Next.js and, in my opinion, for full-stack development in general.</p>
<h3 id="heading-the-caveats-and-criticisms-of-server-actions-a-reality-check">The Caveats and Criticisms of Server Actions: A Reality Check</h3>
<p>Like any technology, they have their downsides, and it’s important to go in with eyes wide open. I’ve learned a few things the hard way, and I’m here to share them.</p>
<p>One of the biggest criticisms is the potential for <strong>tight coupling</strong>. When your server-side code lives right inside your components, it’s easy to end up with a less modular, harder-to-maintain codebase. Changes to your backend logic might force you to update your frontend, and vice versa. For complex projects or teams that need a strict separation of concerns, this can be a real problem. You need to be disciplined and organized to prevent your codebase from becoming a tangled mess.</p>
<p>Then there’s the <strong>learning curve</strong>. While the basic idea of Server Actions is simple, mastering all the nuances — serialization, caching, error handling — takes time. You need to really understand the difference between client and server code execution and how to structure your actions for optimal performance and security. The mental model is different, and it takes some getting used to.</p>
<p>Debugging can also be a pain. When something goes wrong in a Server Action, you can’t just rely on your trusty browser dev tools. You’ll need to get comfortable with server-side debugging techniques — logging, tracing, and so on. Next.js has improved its error messages, but it’s still more complex than debugging client-side code.</p>
<p>Performance is generally a plus with Server Actions, but if you overuse them, you can actually make things <em>worse</em>. Every Server Action call is a network request. Too many requests and your app will feel sluggish. Next.js’s caching helps, but you need to be strategic about it. They’re great for handling data mutations but might not be ideal for complex queries or aggregations.</p>
<p>Finally, there’s the issue of vendor lock-in. Server Actions are a Next.js thing. If you decide to move away from Next.js in the future, you’ll have to rewrite all your Server Actions. That’s something to consider, especially if you’re worried about long-term flexibility.</p>
<p>So, are Server Actions worth it despite these drawbacks? In my opinion, yes, but they’re not a magic solution. You need to use them thoughtfully and understand their limitations. They’re a powerful tool, but like any tool, they can be misused. They are best used for data mutations and operations that are tightly coupled to your UI and need to be on the server.</p>
<h3 id="heading-when-to-use-server-actions">When to use Server Actions</h3>
<ul>
<li><p><strong>Event handling / Performing Database Mutations</strong></p>
<p>  Server actions allow you to perform server operations and database mutations securely without exposing database logic or credentials to the client. They drastically reduce and simplify your code because they remove the need to write a specific API route for your operations.</p>
<pre><code class="lang-javascript">  <span class="hljs-string">'use server'</span>;
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleServerEvent</span>(<span class="hljs-params">eventData: any</span>) </span>{
    <span class="hljs-comment">// Process any server event</span>
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> someAsyncOperation(eventData);
    <span class="hljs-keyword">if</span> (!res.ok) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to handle event'</span>);
    }  
    <span class="hljs-keyword">return</span> { res, <span class="hljs-attr">message</span>: <span class="hljs-string">'Server event handled successfully'</span> };
  }
</code></pre>
</li>
<li><p><strong>Handling form submissions</strong></p>
<p>  Similar to the first point, Server Actions are particularly useful for <strong>processing form inputs</strong> that need server-side handling. They provide a straightforward way to handle form data on the server, ensuring data validation and integrity without exposing the logic to the client and without having to implement elaborate API endpoints.</p>
<pre><code class="lang-javascript">  <span class="hljs-string">'use server'</span>;
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleFormSubmit</span>(<span class="hljs-params">formData: FormData</span>) </span>{
    <span class="hljs-keyword">const</span> name = formData.get(<span class="hljs-string">'name'</span>) <span class="hljs-keyword">as</span> string;
    <span class="hljs-keyword">const</span> email = formData.get(<span class="hljs-string">'email'</span>) <span class="hljs-keyword">as</span> string;
    <span class="hljs-keyword">const</span> message = formData.get(<span class="hljs-string">'message'</span>) <span class="hljs-keyword">as</span> string;
    <span class="hljs-comment">// Process the form data</span>

    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> saveToDatabase({ name, email, message });
    <span class="hljs-keyword">if</span> (!res.ok) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to process the form data'</span>);
    }  
    <span class="hljs-keyword">return</span> { res, <span class="hljs-attr">message</span>: <span class="hljs-string">'Form submitted successfully'</span> };
  }
</code></pre>
</li>
<li><p><strong>Fetching data from client components</strong></p>
<p>  Server Actions can also be useful for <strong>quick data fetching</strong>, where a clean developer experience (DX) is crucial. It can simplify the fetch process by typing data access directly to a component without the need for intermediary API layers. Moreover, when using Typescript, Server Actions make <strong>using types seamless</strong> because everything is within the same function boundary.</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// Simple server action to fetch data from an API</span>
  <span class="hljs-string">'use server'</span>;

  <span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/data'</span>);
    <span class="hljs-keyword">if</span> (!res.ok) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to fetch data'</span>);
    }
    <span class="hljs-keyword">return</span> res.json();
  }
</code></pre>
<p>  Working with Next.js and its server component, you already have this very practical way of using server-side code to fetch data and pre-render the page on the server.</p>
<p>  But Server Action now introduces a brand new way to also do that from your client-side components! It can simplify the fetch process by typing data access directly to the component that needs it, without the need to use <code>useEffects</code> hooks or client-side data fetching libraries.</p>
<p>  Moreover, when using TypeScript, Server Actions make typing seamless because everything is within the same function boundary, providing a great developer experience overall.</p>
</li>
</ul>
<h3 id="heading-potential-pitfalls-with-server-actions">Potential Pitfalls with Server Actions</h3>
<ol>
<li><strong>Don’t use server actions from your server-side components</strong></li>
</ol>
<p>The simplicity and great DX of Server Actions could make it tempting to use them everywhere, including from a server-side component, and it would work! However, it <strong>doesn't really make any sense</strong>. Indeed, since your code is already running on the server, you already have the means to fetch anything you need and provide it as props to your page. Using Server Actions here would <strong>delay data availability</strong> as it causes extra network requests.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734862936786/ce2c7bda-8369-4ee7-9a93-9aaa1674e118.png" alt class="image--center mx-auto" /></p>
<p>For client-side fetching, Server Actions might also not be the best option. First of all, they always automatically use <strong>POST requests</strong>, and they can not be cached automatically like a GET request. Secondly, if your app needs advanced <strong>client-side caching</strong> and <strong>state management</strong>, using tools like <strong>TanStack Query</strong> (React Query) or <strong>SWR</strong> is going to be way more effective for that. However, I haven’t tested it myself yet, but it’s apparently possible to combine both and use TanStack Query to call your server actions directly.</p>
<ol start="2">
<li><strong>Server Actions Do Not Hide Requests</strong></li>
</ol>
<p>Be extremely careful when using server actions for sensitive data. Server Actions <strong>do not hide or secure</strong> your API requests. Even though Server Actions handle server-side logic, under the hood, they are just another API route, and POST requests are handled automatically by Next.js.</p>
<p><strong>Anyone can replicate them</strong> by using a Rest Client, making it essential to validate each request and authenticate users appropriately. If there is sensitive logic involved, ensure you have <code>proper authentication and authorization checks</code> within your Server Actions.</p>
<p>Note: Additionally, consider using the very popular <a target="_blank" href="https://next-safe-action.dev/">next-safe-actions</a> package, which can help secure your actions and also provide type safety.</p>
<ol start="3">
<li><strong>Every Action Adds Server Load</strong></li>
</ol>
<p>Using Server Actions might feel convenient, but every action <strong>comes at a cost</strong>. The more you offload onto the server, the greater the demand for server resources. You may inadvertently increase your <strong>app’s latency</strong> and <strong>cloud cost</strong> by using Server Actions when client-side processing would suffice. Lightweight operations that could easily run on the client, like formatting dates, sorting data, or managing small UI state transitions, should stay on the client side to keep your server load minimal.</p>
<ol start="4">
<li><strong>Classic API Routes Might Be More Appropriate</strong></li>
</ol>
<p>There are cases when sticking with traditional API routes makes more sense, particularly when you need your API to be accessible to <strong>multiple clients</strong>. Imagine if you need the same logic for both your web app and a mobile app, duplicating the same Server Action logic into an API route will only double the work and maintenance. In these situations, having a centralized API route that all clients can call is a better solution, as <strong>it avoids redundancy and ensures consistency</strong> across your different clients.</p>
<ol start="5">
<li><strong>Next.js Dependency and the Moving Target</strong></li>
</ol>
<p>It’s important to note that Server Actions are <strong>closely integrated with Next.js</strong>, and both Next.js and React are evolving rapidly. This pace of development can introduce <strong>compatibility issues</strong> or <strong>breaking changes</strong> as these frameworks continue to update. If your application prioritizes stability and long-term support, relying heavily on cutting-edge features like Server Actions <strong>could result in unwanted technical debt</strong>. Weighing the stability of traditional, well-established methods against the appeal of new features is always advisable.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734866205489/edbf1cd4-1639-479f-a946-b135114a0c19.avif" alt class="image--center mx-auto" /></p>
<h3 id="heading-nextjs-server-actions-mistakes">Next.js Server Actions Mistakes</h3>
<p>So, you have jumped on the Server Actions bandwagon. And, why wouldn’t you? They are fantastic. The feeling of just writing a simple async function right in your component and having us just work in pure magic.</p>
<p>It simplifies our code, reduces boilerplate, and feels like the future of data mutations in Next.js.</p>
<p>But, here is a thing: with great power comes great responsibility. It’s incredibly easy to fall into traps that silently murder your app’s performance and user experience.</p>
<p>I have made these mistakes myself, and I have seen them in code reviews.</p>
<p>Let’s break down the five biggest performance-killers, and more importantly, how to fix them.</p>
<ol>
<li><strong>Not using</strong> <code>useTransition</code> <strong>for Pending States</strong></li>
</ol>
<p>This is the most common rookie mistake (I was this rookie). You call your Server Actions and … nothing happens. The user clicks on the Submit button again and again, thinking it didn’t work. Behind the scenes, the action is running, but the UI provides zero feedback.</p>
<p>The Problem: No Immediate Feedback</p>
<p>Without wrapping your action in useTransition, you have no easy way to show a loading spinner, disable the button, or provide any indication that work is processing. This led to a poor user experience and often to duplicate submissions.</p>
<p>The Lazy Code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/components/AddToCart.jsx</span>
<span class="hljs-string">'use client'</span>;

<span class="hljs-keyword">import</span> { addToCart } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/app/actions'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddToCart</span>(<span class="hljs-params">{ productId }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;button onClick={<span class="hljs-function">() =&gt;</span> addToCart(productId)}&gt;
      Add to Cart
    &lt;/button&gt;
    <span class="hljs-comment">// User has no idea if it worked or is working!</span>
  );
}
</code></pre>
<p>The Performance-Friendly Fix:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/components/AddToCart.jsx</span>
<span class="hljs-string">'use client'</span>;

<span class="hljs-keyword">import</span> { useTransition } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { addToCart } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/app/actions'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddToCart</span>(<span class="hljs-params">{ productId }</span>) </span>{
  <span class="hljs-keyword">const</span> [isPending, startTransition] = useTransition(); <span class="hljs-comment">// 👈 Hook here</span>

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">() =&gt;</span> {
    startTransition(<span class="hljs-function">() =&gt;</span> { <span class="hljs-comment">// 👈 Wrap the action</span>
      addToCart(productId);
    });
  };

  <span class="hljs-keyword">return</span> (
    &lt;button onClick={handleClick} disabled={isPending}&gt;
      {isPending ? <span class="hljs-string">'Adding...'</span> : <span class="hljs-string">'Add to Cart'</span>}
    &lt;/button&gt;
    <span class="hljs-comment">// 👍 User now gets clear feedback!</span>
  );
}
</code></pre>
<p>By using <code>useTransition</code>, you make the interface responsive and prevent the user from spamming your server action.</p>
<ol start="2">
<li><strong>Skipping Validation on the Client</strong></li>
</ol>
<p>Server Actions run on the server. This is where your final, absolute validation should happen. However, waiting for a full network round-trip to tell the user they forgot to fill in a required field is a waste of time and resources.</p>
<p>The Problem: Unnecessary Network Requests.</p>
<p>You are sending a request to the server just for it to immediately send back a validation error. This consumes your server’s bandwidth and processing power for something that could have been caught instantly on the client.</p>
<p>The Lazy Code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// A form with no client-side validation</span>
&lt;form action={submitForm}&gt;
  &lt;input name=<span class="hljs-string">"email"</span> <span class="hljs-keyword">type</span>=<span class="hljs-string">"email"</span> /&gt;
  &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Sign Up&lt;/button&gt;
&lt;/form&gt;
</code></pre>
<p>The Performance-Friendly Fix:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Using simple HTML5 validation</span>
&lt;form action={submitForm}&gt;
  &lt;input name=<span class="hljs-string">"email"</span> <span class="hljs-keyword">type</span>=<span class="hljs-string">"email"</span> required /&gt; {<span class="hljs-comment">/* 👈 `required` attribute */</span>}
  &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Sign Up&lt;/button&gt;
&lt;/form&gt;

<span class="hljs-comment">// Or, using a more robust hook (pseudo-code)</span>
<span class="hljs-string">'use client'</span>;
<span class="hljs-keyword">import</span> { useForm } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-hook-form'</span>;
<span class="hljs-keyword">import</span> { zodResolver } <span class="hljs-keyword">from</span> <span class="hljs-string">'@hookform/resolvers/zod'</span>;
<span class="hljs-keyword">import</span> { submitForm } <span class="hljs-keyword">from</span> <span class="hljs-string">'./actions'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { register, handleSubmit, formState: { errors, isSubmitting } } = useForm({
    resolver: zodResolver(validationSchema), <span class="hljs-comment">// Catches errors on client first</span>
  });

  <span class="hljs-keyword">const</span> onSubmit = <span class="hljs-keyword">async</span> (data) =&gt; {
    <span class="hljs-comment">// This action only runs if client-side validation passes!</span>
    <span class="hljs-keyword">await</span> submitForm(data);
  };

  <span class="hljs-keyword">return</span> (
    &lt;form onSubmit={handleSubmit(onSubmit)}&gt;
      &lt;input {...register(<span class="hljs-string">'email'</span>)} /&gt;
      {errors.email &amp;&amp; &lt;p&gt;{errors.email.message}&lt;/p&gt;}
      &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span> disabled={isSubmitting}&gt;Sign Up&lt;/button&gt;
    &lt;/form&gt;
  );
}
</code></pre>
<p>Catch errors on the client to save precious server cycles for the real work.</p>
<ol start="3">
<li><strong>Forgetting to Add</strong> <code>revalidatePath</code> <strong>or</strong> <code>revalidateTag</code></li>
</ol>
<p>This mistake doesn’t make your app slow; it makes it wrong. Server Actions often change data (e.g., adding a todo, updating a name). If you don’t tell Next.js to refetch the data that was changed, your UI will show stale information.</p>
<p>The Problem: State Data After Mutation</p>
<p>The user adds a new item, the action succeeds, but the list doesn’t update. They refresh the page to see their changes. This breaks the immersive “app-like“ feel.</p>
<p>The Lazy Code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions/todos.js</span>
<span class="hljs-string">'use server'</span>;

<span class="hljs-keyword">import</span> { createTodo } <span class="hljs-keyword">from</span> <span class="hljs-string">'./db-lib'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addTodo</span>(<span class="hljs-params">formData</span>) </span>{
  <span class="hljs-keyword">const</span> todo = <span class="hljs-keyword">await</span> createTodo(formData);
  <span class="hljs-comment">// ❌ The `/` page still has the old list of todos!</span>
  <span class="hljs-keyword">return</span> todo;
}
</code></pre>
<p>The Performance-Friendly Fix:</p>
<p>Always revalidate the data cache after a mutation.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions/todos.js</span>
<span class="hljs-string">'use server'</span>;

<span class="hljs-keyword">import</span> { createTodo } <span class="hljs-keyword">from</span> <span class="hljs-string">'./db-lib'</span>;
<span class="hljs-keyword">import</span> { revalidatePath } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/cache'</span>; <span class="hljs-comment">// 👈 Import this!</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addTodo</span>(<span class="hljs-params">formData</span>) </span>{
  <span class="hljs-keyword">const</span> todo = <span class="hljs-keyword">await</span> createTodo(formData);
  revalidatePath(<span class="hljs-string">'/'</span>); <span class="hljs-comment">// 👈 Tell Next.js to re-fetch the home page</span>
  <span class="hljs-comment">// or revalidateTag('todos') if using fetch tags</span>
  <span class="hljs-keyword">return</span> todo;
}
</code></pre>
<p>This ensures your UI is always in sync with your database without requiring a full page reload.</p>
<ol start="4">
<li><strong>Importing Heavy Client-Side Libraries in Server Actions</strong></li>
</ol>
<p>Server Actions are server-side code. They run in the Node.js environment. If you import a massive client-side library, like a full PDF generator, a browser-specific charting library, or even a component, you will bloat your server bundle and likely cause runtime errors.</p>
<p>The Problem: Massive Server Bundle &amp; Runtime Crashes</p>
<p>You’ll see errors like <code>window is not defined</code> or <code>document is not defined</code> because those browser APIs don’t exist in Node. Even if it doesn’t crash, you are shipping a huge amount of unused JS to your server.</p>
<p>The Lazy Code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions/generate-pdf.js</span>
<span class="hljs-string">'use server'</span>;

<span class="hljs-keyword">import</span> { heavyPdfLibrary } <span class="hljs-keyword">from</span> <span class="hljs-string">'client-side-pdf-lib'</span>; <span class="hljs-comment">// ❌ This will break!</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generatePdf</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-comment">// `heavyPdfLibrary` uses `window`, this will throw an error.</span>
  <span class="hljs-keyword">return</span> heavyPdfLibrary.generate(data);
}
</code></pre>
<p>The Performance-Friendly Fix:</p>
<p>Use server-side compatible libraries and be ruthless about your imports.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions/generate-pdf.js</span>
<span class="hljs-string">'use server'</span>;

<span class="hljs-comment">// ✅ Choose a server-side compatible library</span>
<span class="hljs-keyword">import</span> { pdf } <span class="hljs-keyword">from</span> <span class="hljs-string">'@react-pdf/renderer'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generatePdf</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-comment">// Use the server-safe library</span>
  <span class="hljs-keyword">const</span> pdfStream = <span class="hljs-keyword">await</span> pdf(&lt;MyDocument data={data} /&gt;).toBuffer();
  <span class="hljs-keyword">return</span> pdfStream;
}
</code></pre>
<p>Always check if a library is designed for the server. When in doubt, look for <code>ssr</code> or <code>node</code> in its documentation.</p>
<ol start="5">
<li><strong>Making Sequential Instead of Parallel Calls</strong></li>
</ol>
<p>This is a classic async/await mistake that’s easy to make anywhere, including Server Actions. If you have multiple independent operations, waiting for each one to finish before starting the next is a huge waste of time.</p>
<p>The Problem: Adding Unnecessary Delay</p>
<p>If each operation takes 100ms, doing three of them sequentially takes <em>at least</em> 300ms. Doing them in parallel takes <em>at most</em> ~100ms.</p>
<p>The Lazy Code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions/checkout.js</span>
<span class="hljs-string">'use server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">finalizeOrder</span>(<span class="hljs-params">orderId</span>) </span>{
  <span class="hljs-comment">// These operations don't depend on each other...</span>
  <span class="hljs-keyword">const</span> auditLog = <span class="hljs-keyword">await</span> writeToAuditLog(orderId); <span class="hljs-comment">// Waits for this to finish...</span>
  <span class="hljs-keyword">const</span> email = <span class="hljs-keyword">await</span> sendConfirmationEmail(orderId); <span class="hljs-comment">// ...then waits for this...</span>
  <span class="hljs-keyword">const</span> analytics = <span class="hljs-keyword">await</span> updateAnalytics(orderId); <span class="hljs-comment">// ...and finally this.</span>

  <span class="hljs-keyword">return</span> { auditLog, email, analytics };
}
<span class="hljs-comment">// Total time ~300ms+</span>
</code></pre>
<p>The Performance-Friendly Fix:</p>
<p>Use <code>Promise.all</code> to run independent operations in parallel.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions/checkout.js</span>
<span class="hljs-string">'use server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">finalizeOrder</span>(<span class="hljs-params">orderId</span>) </span>{
  <span class="hljs-comment">// Kick off all three promises at once</span>
  <span class="hljs-keyword">const</span> [auditLog, email, analytics] = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all([
    writeToAuditLog(orderId),
    sendConfirmationEmail(orderId),
    updateAnalytics(orderId),
  ]);

  <span class="hljs-keyword">return</span> { auditLog, email, analytics };
}
<span class="hljs-comment">// Total time ~100ms+</span>
</code></pre>
<p>This simple change can dramatically reduce the response time of your Server Actions.</p>
<h3 id="heading-real-world-example-add-to-cart">Real-World Example: Add to Cart</h3>
<p>Let’s see how Server Actions can be applied in a real-world scenario. Imagine we’re building an e-commerce platform, and we need a feature to add products to a shopping cart. Here’s how we could implement it using a Server Action, incorporating some crucial best practices along the way.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions.ts</span>

<span class="hljs-string">"use server"</span>;

<span class="hljs-keyword">import</span> { db } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/lib/db"</span>; <span class="hljs-comment">// Your database client</span>
<span class="hljs-keyword">import</span> { revalidatePath } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/cache"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addItemToCart</span>(<span class="hljs-params">userId: <span class="hljs-built_in">string</span>, productId: <span class="hljs-built_in">string</span>, quantity: <span class="hljs-built_in">number</span></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Input validation</span>
    <span class="hljs-keyword">if</span> (!userId || !productId || quantity &lt;= <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Invalid input data"</span>);
    }

    <span class="hljs-comment">// Check for product existence</span>
    <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> db.product.findUnique({
      where: { id: productId },
    });

    <span class="hljs-keyword">if</span> (!product) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Product not found"</span>);
    }

    <span class="hljs-comment">// Handle the cart item</span>
    <span class="hljs-keyword">const</span> existingCartItem = <span class="hljs-keyword">await</span> db.cartItem.findFirst({
      where: { userId, productId },
    });

    <span class="hljs-keyword">if</span> (existingCartItem) {
      <span class="hljs-keyword">await</span> db.cartItem.update({
        where: { id: existingCartItem.id },
        data: { quantity: existingCartItem.quantity + quantity },
      });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">await</span> db.cartItem.create({
        data: { userId, productId, quantity },
      });
    }

    <span class="hljs-comment">// Cache revalidation to reflect the changes on the pages</span>
    revalidatePath(<span class="hljs-string">`/products/<span class="hljs-subst">${productId}</span>`</span>);
    revalidatePath(<span class="hljs-string">`/cart`</span>);

    <span class="hljs-keyword">return</span> { success: <span class="hljs-literal">true</span>, message: <span class="hljs-string">"Item added to cart"</span> };
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error adding item to cart:"</span>, error);

    <span class="hljs-comment">// Handle errors gracefully</span>
    <span class="hljs-keyword">return</span> { success: <span class="hljs-literal">false</span>, message: <span class="hljs-string">"Failed to add item to cart"</span> };
  }
}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/components/AddToCartButton.tsx</span>

<span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { addItemToCart } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/app/actions"</span>;
<span class="hljs-keyword">import</span> { useSession } <span class="hljs-keyword">from</span> <span class="hljs-string">"next-auth/react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddToCartButton</span>(<span class="hljs-params">{ productId }: { productId: <span class="hljs-built_in">string</span> }</span>) </span>{
  <span class="hljs-keyword">const</span> { data: session } = useSession();
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [message, setMessage] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-keyword">async</span> () =&gt; {
    setLoading(<span class="hljs-literal">true</span>);
    setMessage(<span class="hljs-string">""</span>);

    <span class="hljs-comment">// Call the Server Action, passing data and handling the result</span>
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> addItemToCart(session?.user?.id, productId, <span class="hljs-number">1</span>);

    setLoading(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">if</span> (result.success) {
      setMessage(result.message);
      <span class="hljs-comment">// or other side effects</span>
    } <span class="hljs-keyword">else</span> {
      setMessage(<span class="hljs-string">"Error adding item to cart"</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;button onClick={handleClick} disabled={loading}&gt;
        {loading ? <span class="hljs-string">"Adding..."</span> : <span class="hljs-string">"Add to Cart"</span>}
      &lt;/button&gt;
      {message &amp;&amp; &lt;p&gt;{message}&lt;/p&gt;}
    &lt;/div&gt;
  );
}
</code></pre>
<p>This example demonstrates a few key best practices:</p>
<ul>
<li><p><strong>Input Validation:</strong> The Server Action validates the input to prevent errors and security vulnerabilities.</p>
</li>
<li><p><strong>Error Handling:</strong> The <code>try...catch</code> block ensures that errors are handled gracefully and informative messages are returned to the client.</p>
</li>
<li><p><strong>Database Interaction:</strong> We use a hypothetical database client (<code>db</code>) to interact with the database. In a real app, you'd likely use an ORM like Prisma.</p>
</li>
<li><p><strong>Cache Revalidation:</strong> We use <code>revalidatePath</code> to keep the product and cart pages up-to-date.</p>
</li>
<li><p><strong>UI Logic Separation:</strong> The <code>AddToCartButton</code> component handles the UI and user interactions, keeping the Server Action focused on data and server-side logic.</p>
</li>
</ul>
<p>This streamlined example showcases how Server Actions can simplify common e-commerce tasks while adhering to essential best practices. Remember to modularize your actions, keep UI logic separate, and always validate user inputs. While this provides a good starting point, more complex scenarios might require more sophisticated error handling, caching strategies, and database interactions.</p>
<p><a target="_blank" href="https://medium.com/@sureshdotariya/how-we-reduced-ttfb-by-60-using-server-actions-in-next-js-15-web-application-1cd0d37eed01">https://medium.com/@sureshdotariya/how-we-reduced-ttfb-by-60-using-server-actions-in-next-js-15-web-application-1cd0d37eed01</a></p>
<p><a target="_blank" href="https://medium.com/@sureshdotariya/next-js-15-mastery-series-part-2-server-actions-a7939ca5514e">https://medium.com/@sureshdotariya/next-js-15-mastery-series-part-2-server-actions-a7939ca5514e</a></p>
<h2 id="heading-what-use-client-really-does-in-react-or-nextjs">What “use client“ Really Does in React or Next.js</h2>
<p>React’s “use client“ directive might look like an annotation at the top of your file, but it presents a profound shift in how we structure applications. Ever since Next.js 13 introduced a new app router and React Server Components, developers have been grappling with these two-word directives. On the surface, “use client“ marks a component to run on the browser. Under the hood, however, it opens a gateway between the server and client environments in a way that’s both elegant and technically sophisticated. In fact, React core team member <a target="_blank" href="https://overreacted.io/what-does-use-client-do">Dan Abramov argues</a> that the invention of <code>use client</code>(and its counterparts, “use server“) It is as fundamental as the introduction of async/await or even structured programming itself. That is a bold claim for the little string at the top of the file. So, what does “use client“ really do? And, why is it so important for the future of React?</p>
<h3 id="heading-from-server-to-client-bringing-two-worlds">From Server to Client: Bringing Two Worlds</h3>
<p>To understand the meaning of “use client“, it helps to consider the context in which it emerged. In Next.js 13 App Router, components are server-first by default. This means if you write a component without any directives, Next.js will render it on the server (producing static HTML) and send that HTML to the browser without any client-side JavaScript for that component. This is great for performance. Your pages can load with minimal JS, but it poses challenges when you do need interactivity or state. How do we tell React that a certain component (say, a counter button or a dynamic form) needs to be interactive and runs on the browser? That’s exactly what “use client“is for.</p>
<p>When you add “use client“ to the top of the file (above any imports), you are declaring that this module and everything it imports should be treated as a Client Component, meaning it will execute on the client side and can use interactive features like state, effects, and browser APIs. In essence, “use client“ draws a boundary line in your app’s module graph, on one side of that line, components run on the server; on the other side, components run on the client. This directive flips the historical default. In traditional React apps (and in Next.js’s old Page Router), every component was a client-side component by default, and you opted into server rendering. Now, with server components, we default to running on the server and explicitly opt into the client side for interactive parts.</p>
<p>Crucially, “use client“ is more than a marker for “put this code in the browser“. It serves as a bridge between two environments. A way for the server to include client-run code in the app’s output in a controlled, declarative manner. Dan Abramov describes “use client“ as essentially a typed &lt;script&gt; tag. Just as a script tag in HTML tells the browser to execute some bundled JavaScript, “use client“ tells React’s tooling that “This module is UI code that the browser needs“. The server can import that module and hand off rendering to it, much like opening the door from the server world into the client world. In other words, “use client“ allows the server to reach into the client bundle and say, “I need this component to come alive in the browser.“. It’s a formal, first-class way to intertwine server-rendered content with client-side interactivity.</p>
<h3 id="heading-how-does-use-clientwork-under-the-hood">How does “use client“work under the hood?</h3>
<p>The technical mechanics of “use client“ are fascinating. When you mark a module with “use client“, you are signaling to the build system and to React that this file (and its dependencies) belong in the client bundle. If a Server Component tries to import something from that file, the server won’t import the component’s implementation directly. Instead, it imports a stub or reference to it. Think of it like a placeholder or a token that stands in for the real component. The server-rendered output will include a pointer to that client component rather than the component’s HTML, indicating, “there is a client component here, which will be rendered on the client side“. React’s server component payload (often a special JSON behind the scenes) might include an identifier for the component, such as a module path and export name. For example, the server output could contain something like:</p>
<pre><code class="lang-typescript">{
  <span class="hljs-string">"type"</span>: <span class="hljs-string">"/src/frontend.js#LikeButton"</span>,
  <span class="hljs-string">"props"</span>: { <span class="hljs-string">"postId"</span>: <span class="hljs-number">42</span>, <span class="hljs-string">"likeCount"</span>: <span class="hljs-number">8</span>, <span class="hljs-string">"isLiked"</span>: <span class="hljs-literal">true</span> }
}
</code></pre>
<p>This is not literal HTML, but a description. It says there should be a <code>&lt;LikeButton&gt;</code> there with those props, and it references the component by module (<code>/src/frontend.js</code>) and name (<code>LikeButton</code>)​. The React runtime uses this to generate actual script tags for the browser. When the response reaches the client, the framework knows it needs to load the <code>/src/frontend.js</code> module (the file where <code>LikeButton</code> is defined) as a separate JavaScript chunk. It injects a <code>&lt;script src="frontend.js"&gt;&lt;/script&gt;</code> for that file, and once loaded, it hydrates the component by calling <code>LikeButton({...props})</code> on the client. In essence, the “use client“ directive allows the server to embed a reference to a client-side component in its output, and that reference is resolved into a real interactive UI in the browser.</p>
<p>One important nuance is that making a component with “use client“ directive does not meant it won’t be rendered on the server at all. In fact, Next.js will still pre-render the initial HTML for client components in many cases (just like it did in the old pages architecture) and then hydrate them on the client. The “use client“ directive simply ensures that the component’s JavaScript is sent to the browser and React knows to hydrate it. That means you don’t lose the SEO and performance benefits of server-side rendering by using a Client Components; you are just opting into sending additional JS for interactivity. A common rookie mistake is thinking that adding “use client“ makes your entire page purely client-side rendered. In reality, a Client Component is Next.js 13+ is usually still rendered to HTML on the server first, then made interactive on the client, which is exactly how React pages have traditionally worked. This big difference is that now you have a choice, part of the page with no “use client“stays purely server-rendered (no hydration needed at all), and parts with “use client“ get that two-step treatment of SSR + hydration.</p>
<p>Because of how the boundaries work, you typically only need to put “use client“ at the top of entry points for interactive islands of your application. Once you mark a component as a Client Component, all of its children and imports automatically become part of the client bundle as well. You do not need to “use client“ on every file that contains a hook or browser API call. For example, if you create a <code>Counter.tsx</code> component with <code>'use client'</code> (so it can use <code>useState</code> and handle clicks) and then import it into a parent server-rendered page, so that Counter and anything it imports will be bundled for the client. If that Counter itself renders other components(passed in as children or imported within it), those can actually be server components if they don’t need interactivity. React will seamlessly render those on the server and slot their HTML into the client’s component output before hydration. This flexibility can be mind-bending. You can have a Server Component inside a Client Component, which is inside a Server Component, and so on. The framework’s job is to sort out which parts run where. As developers, our job is just to label the boundaries correctly. And thanks to <code>'use client'</code>, those boundaries are explicit and easy to reason about.</p>
<h3 id="heading-why-use-client-matters-more-than-you-might-think"><strong>Why</strong> <code>use client</code> Matters (More Than You Might Think)</h3>
<p>The introduction of <code>'use client'</code> has significant implications for how we architect React applications, especially in frameworks like Next.js. First and foremost, it enables fine-grained performance optimization. By defaulting everything to server-rendered and then opting specific pieces into client-side hydration, we send far less JavaScript to the browser than a traditional SPA would. A page that might have previously bundled the logic of every component can now ship only the code for truly interactive parts. This “eat your cake and have it too” approach, full server rendering for most of the UI, and rich interactivity where needed, is essentially an implementation of the elusive ideal of progressive hydration or the so-called “islands architecture.” You can think of each <code>'use client'</code> component as an island of interactivity amid a sea of purely server-rendered HTML. If a part of your UI doesn’t need interactivity, simply leave out the directive and it remains an island of static content (no hydration overhead)​. This leads to better loading performance and less JavaScript bloat on the client. Next.js 13+’s architecture actively encourages this. It makes you consciously add <code>'use client'</code> only where necessary, nudging you into keeping most of your UI logic on the server by default.</p>
<p>Second, <code>'use client'</code> improves the developer experience and code maintainability in a full-stack React app. In the past, to make a client-side interactive widget that also fetched or updated data on the server, you had to write a lot of boilerplate. Define an API route or endpoint, call <code>fetch</code> from the client, handle state for loading or errors, and so on. Now, consider the new world with Server and Client Components. The server can render a component and pass it data directly as props, and the client component can, in turn, directly call back to server functions (using <code>'use server'</code>, which goes hand-in-hand with <code>'use client'</code>). In Dan Abramov’s Like button example, instead of manually writing API endpoints for “like” and “unlike” and then writing client code to fetch those, you can simply write a server function <code>likePost</code> and import it into your client component with <code>'use server'</code>. React will handle turning that into an API call for you. On the flip side, you write a <code>LikeButton</code> component with <code>'use client'</code> and import it into your server-rendered UI; React will handle sending that component’s code to the browser and hydrating it​. The connection is expressed through the module system (via import/export), not through ad-hoc API contracts. This means your editor and type system can understand the relationship. You can navigate to definitions, get type checking across the boundary, and treat the client–server interaction as a function call rather than a network call. As Abramov puts it, the <code>'use client'</code> import “expresses a direct connection within the module system” between the part of the program that sends the <code>&lt;script&gt;</code> (server) and the part that lives inside that script (client), making it fully visible to tools and type-checkers. In practical terms, this can reduce bugs and make code more discoverable compared to the old way of string-typed API endpoints.</p>
<p>Using <code>'use client'</code> also forces a clearer separation of concerns between your purely presentational/server-driven components and your interactive ones. In a large codebase, this can be a healthy discipline. You might designate most of a page (navigation bars, content sections, data displays) as server-rendered and free of client-side logic, and only sprinkle a few <code>'use client'</code> components for things like forms, modals, or widgets that truly need it. Those client components can still leverage server-side data by receiving props or calling server actions, but they won’t inadvertently drag the entire page’s code into the client bundle. Many developers, upon first migrating to Next 13+, felt it was annoying to add <code>'use client'</code> everywhere they used hooks. But this “annoyance” is intentional. It makes you stop and consider “Does this code really need to run on the client?”. If not, perhaps it could be refactored to a server component, leaving just a tiny client component for the interactive bit. In time, teams find that this leads to smaller, more purpose-driven client modules and a more robust rendering strategy. It’s a new mental model, but one that aligns with the performance needs of modern apps.</p>
<p>One caution, because <code>'use client'</code> scopes an entire module to the client, you do have to be mindful about what you import inside a client module. Anything you import into a <code>'use client'</code> file becomes part of the client-side bundle (unless it’s a purely type import or something that gets compiled away). This means you wouldn’t want to import a Node-only library or a huge server-only module inside a client component. It either won’t work (if it relies on Node APIs) or it will bloat your bundle. Next’s compiler will usually warn or error if you try to import server-only code into a client module. In short, keep client components focused and lean. Use them for UI and interactivity, not heavy data fetching or processing (those belong on the server side). Fortunately, the system makes this natural: heavy data fetching is easier to do in Server Components, and they can feed the results into Client Components as props. The end result is an app that is modularized by environment**,** server logic and rendering over here, client logic and interaction over there, both living in the same codebase but clearly delineated.</p>
<h3 id="heading-the-future-of-use-client-and-the-react-ecosystem"><strong>The Future of</strong> <code>'use client'</code> and the React Ecosystem</h3>
<p>It’s early days for React Server Components and the <code>'use client'</code> directive, but the impact is already being felt. As of Next.js 13+ (and the evolving React 18+ ecosystem), we’re seeing a rethinking of how UI and backend logic intermingle. The success of these directives could influence other frameworks and the broader web platform in interesting ways. Dan Abramov suggests that the ideas behind <code>'use client'</code>/<code>'use server'</code> are not limited to React; they are a generic approach to distributed applications, essentially a form of RPC (remote procedure call) built into the module system. Imagine a future where your codebase seamlessly spans multiple runtimes (web browser, server, maybe even mobile or worker contexts), with the boundaries declared in the code and handled by compilers and bundlers. The React team expects these patterns to “survive past React and become common sense” in web development. It’s a bold vision, a world where sending code to the client or calling into the server is as straightforward as calling a function, with tools taking care of the messy details of networking and serialization.</p>
<p>In practical terms, the ecosystem is already adapting. Libraries that provide React components are starting to consider how they’ll work in a Server Components world. For example, a date picker or charting library might mark its components with <code>'use client'</code> so that if you use them in a Next 13+ app, the library’s code is correctly included on the client side. Tooling is also improving. Since these directives are just string literals, they rely on build tooling to do the right thing. We might see better ESLint rules or even language support to catch mistakes like forgetting to add <code>'use client'</code> when needed, or conversely, adding it unnecessarily. There’s active discussion in the community about how to make the developer experience smoother. Could future React versions infer <code>'use client'</code> automatically for certain components based on usage of hooks? Possibly, though the React team seems to prefer explicit boundaries for now, as automation might be error-prone. What’s more likely is continued guidance and patterns for structuring apps. Over time, using <code>'use client'</code> may feel as natural as using <code>useState</code>, just another part of React’s vocabulary.</p>
<p>We should also watch for how other frameworks respond. The idea of partial hydration and islands of interactivity isn’t unique to React. Frameworks like Astro, Qwik, and Marko have been exploring similar territory, each with their own spin. React’s approach with <code>'use client'</code> and <code>'use server'</code> is distinctive in that it integrates deeply with JavaScript modules and bundlers, rather than introducing a completely new DSL. This means it could be adopted beyond React if standardized, for instance, a future build tool could allow any JavaScript project to designate certain modules for the client or server environment using similar directives. It’s not hard to imagine the concept spreading: the benefits of clarity, performance, and type safety at the boundary are not something any full-stack developer would want to pass up. On the other hand, React’s solution is opinionated: it assumes a single unified project that produces both server and client artifacts, which fits frameworks like Next.js perfectly. Not every project will have that shape, so there will continue to be alternatives and variations.</p>
<p>In the short term, we can expect the React community to establish best practices around <code>'use client'</code>. Already, the recommendation is to use it sparingly and purposefully. The ideal React Server Components app uses <code>'use client'</code> only components that truly need it, and sometimes that means writing a small wrapper component just to hold some client state or effect while the rest stays on the server. This granularity might feel like extra work, but it pays off in load performance and gives you a clearer understanding of your app’s runtime behavior. There’s also an educational aspect: understanding <code>'use client'</code> inevitably means understanding how the client–server continuum works in a React app, which makes one a better full-stack developer. It forces you to confront where the state lives, where data comes from, and what code runs where. Those who embrace this mindset are likely to build apps that scale better and are easier to debug across environments.</p>
<p>The <em>Yin-Yang</em> of modern React architecture. Many have begun to view their React apps as a yin-yang symbol of server and client, two complementary halves of a single whole. The <code>'use client'</code> and <code>'use server'</code> directives are the two gates that let data and code flow between these halves in a controlled way, each gate opening in one direction​. <code>'use server'</code> lets the client safely invoke server-side functions (essentially turning an import into a network call), while <code>'use client'</code> lets the server include interactive client-side UI (turning an import into a script reference). Together, they allow “seamless composition across the network”​, meaning you can build features that feel like one cohesive program even though under the hood they involve browser code talking to server code. It’s a powerful illusion that improves practicality rather than just abstracting it away: you still <em>know</em> which parts run where, but you no longer have to hand-stitch the plumbing every time you cross the boundary.</p>
<p>In conclusion, <code>'use client'</code> is far more than a mere hint to “do this in the browser.” It is a cornerstone of React’s new architecture, enabling a new level of integration between server and client logic while preserving performance and clarity. Its importance will only grow as more of the React ecosystem adopts Server Components. Yes, it requires learning a new way of thinking about React, one where you occasionally have to pop open a different mental toolbox for client versus server concerns, but the payoff is an application that can be both highly performant and richly interactive. For busy developers working on complex apps, <code>'use client'</code> offers a way to write code that is simultaneously efficient and expressive, bridging worlds that used to be separate. As we continue to refine these patterns, it’s likely that in a few years using <code>'use client'</code> (and <code>'use server'</code>) will feel as natural as writing an async function. It’s a small change with big implications, and it’s pointing the way toward a future in which the line between front-end and back-end code is blurred by design, not by accident. In that future, the phrase “full-stack developer” might take on a more literal meaning, and <code>'use client'</code> will have been one of the keys that opened the door.</p>
<h2 id="heading-nextjs-15-app-router-architecture-and-sequence-flow">Next.js 15 App Router — Architecture and Sequence Flow</h2>
<h3 id="heading-overview-of-server-vs-client-components">Overview of Server vs. Client Components</h3>
<p>Next.js App Router leverages React Server Component (RSC) by default for improved performance. By default, all <code>page</code> and layout <code>files</code> are server components, meaning they render on the server and their code is not sent to the client. Client Components (marked with the “use client“ directive) are used only when interactivity, state, or browser APIs are needed. In practice, a Server Component can include and import a Client Component (to add interactive parts), but not vice versa. This allows a single page’s component tree to interleave server-rendered UI with interactive client-side widgets. By pushing as much UI as possible into Server Components, Next.js reduces the amount of JavaScript that must hydrate on the client, improving performance.</p>
<p><strong>Key Characteristics:</strong></p>
<ul>
<li><p><strong>Server Components</strong>: Render on the server only (never in the browser), can safely access databases, secrets, and perform data fetching with <code>await</code> (e.g. <code>await fetch(...)</code>) directly in the component code. They are never hydrated on the client and <strong>do not include React state or event handlers</strong> (they output static HTML).</p>
</li>
<li><p><strong>Client Components</strong>: Render on the server <em>and</em> then hydrate on the client. These are needed for any stateful or interactive UI (hooks like <code>useState</code>, event handlers, browser-only APIs like <code>window</code> or <code>localStorage</code>). A file with <code>'use client'</code> at the top is treated (and all of its imports) as part of the client-side bundle. During the initial page load, Client Components are still server-side rendered to HTML (for faster first paint), but afterwards their JS code runs in the browser to handle interactivity.</p>
</li>
</ul>
<p><strong>Composition</strong>: Server and Client components can be mixed. For example, a Server Component page might import a <code>&lt;Navbar&gt;</code> that is mostly server-rendered but includes a <code>&lt;SearchBar&gt;</code> marked as a Client Component for interactivity. React will render the Server Components to an RSC Payload (a serialized representation), including placeholders for any Client components. The Client Component’s actual HTML will be injected on the client side during hydration. This lets heavy lifting (data fetching, markup generation) occur on the server, and interactive pieces will be added on the client without a full re-render of the entire page.</p>
<h3 id="heading-app-router-structure-layouts-templates-and-pages">App Router Structure: Layouts, Templates, and Pages</h3>
<p>Next.js organizes routes in <code>/app</code> directory using nested folders. Each folder can contain special files that define the UI for that route segment. The primary ones are: <strong>Layout</strong>, <strong>Template</strong>, and <strong>Page</strong>.</p>
<ul>
<li><p><strong>Layouts (</strong><code>layout.tsx</code><strong>)</strong>: A Layout is a wrapper UI that <strong>persists across pages</strong>. Layouts are defined at any route segment and apply to all pages under that segment. On navigation, layouts do <strong>not</strong> unmount or re-run; they preserve state and remain interactive without rerendering. This means if you have stateful Client Components in a layout (e.g. a sidebar or header), they won’t reset when moving between child pages. Layout files are hierarchical – a child segment’s layout is nested inside its parent layout. The top-level <code>app/layout.tsx</code> is the <strong>Root Layout</strong> (required, must include <code>&lt;html&gt;</code> and <code>&lt;body&gt;</code> tags) wrapping the entire app.</p>
</li>
<li><p><strong>Templates (</strong><code>template.tsx</code><strong>)</strong>: A Template is very similar to a layout in structure (wraps children segments), <strong>but does not persist state across navigations</strong>. Instead, a template <strong>re-mounts afresh for each navigation</strong> even if you stay in the same segment. In effect, it’s a “re-rendered layout” used when you want certain parent UI to reset or run again on each page change. For example, use a Template for an animation or to reset scroll position or state whenever the user navigates between sibling pages. According to Next.js conventions, <em>“template” files are rendered after layouts and before the page component, and a new instance is created when navigating between pages using that same template</em>. (In contrast, layouts “always precede templates” and remain mounted.) <strong>Use-case tip:</strong> Use Layouts by default; use a Template only if you need to <em>reset state or re-run effects</em> on navigation.</p>
</li>
<li><p><strong>Pages (</strong><code>page.tsx</code><strong>)</strong>: A Page is the leaf component for a route – it defines the content for a specific URL. Pages are always Server Components (unless explicitly made client) and can be asynchronous (e.g. to <code>await fetch</code> data). They are rendered as children of the nearest Layout/Template wrappers. Each folder typically contains a single <code>page.tsx</code> (except for dynamic routes). The page component’s output is what ultimately gets rendered inside all the surrounding layouts/templates for that route.</p>
</li>
</ul>
<p><strong>How they compose:</strong> When a user navigates to a URL, Next.js matches a chain of layouts/templates down to the page. For example, consider a route <code>/dashboard/profile</code> with the following structur</p>
<pre><code class="lang-typescript">app/
├─ layout.tsx          (Root Layout – e.g. site chrome) 
└─ dashboard/
    ├─ layout.tsx      (Dashboard Layout – persists <span class="hljs-keyword">for</span> all /dashboard<span class="hljs-comment">/* pages)
    ├─ template.tsx    (Dashboard Template – re-renders on each navigation under /dashboard)
    ├─ page.tsx        (Dashboard index page, e.g. /dashboard)
    └─ profile/
        └─ page.tsx    (Profile Page, at route /dashboard/profile)</span>
</code></pre>
<p>When loading <code>/dashboard/profile</code>, Next.js will:</p>
<ol>
<li><p>Render <code>app/layout.tsx</code> (root layout) at the top,</p>
</li>
<li><p>Inside it, render <code>app/dashboard/layout.tsx</code>,</p>
</li>
<li><p>Then render <code>app/dashboard/template.tsx</code> (its output wrapping the page),</p>
</li>
<li><p>Finally render the <code>app/dashboard/profile/page.tsx</code> content inside those wrappers.</p>
</li>
</ol>
<p>The Root Layout might include the global HTML structure and navigation; the Dashboard layout might include the sidebar that remains persistent; the Template layout could ensure that navigating between sub-pages (Dashboard index and Profile) resets certain state; and the Profile page provides the main page content. Next.js does this assembly automatically based on the folder structure. Notably, layouts render in parallel with pages, meaning the server doesn't block pages until the parent layout is done — this improves performance by avoiding sequential waterfalls.</p>
<h3 id="heading-initial-page-load-request-response-sequence">Initial Page Load: Request-Response Sequence</h3>
<p>On the first load of a page (or a direct visit URL), the sequence involves both server-side rendering and client-side hydration:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753186838344/4638b67f-fc1f-4736-ac81-2bb61b1eaed6.webp" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Browser -&gt; Next.js Server:</strong> The browser requests a page (say <code>/dashboard/profile</code>). This request hits the Next.js server (Node.js or Edge runtime). The App Router locates the matching route segments and loads the corresponding components: all required Layout(s), Template(s), and the Page component for <code>/dashboard/profile</code>.</p>
</li>
<li><p><strong>Server Rendering with RSC:</strong> Next.js performs an SSR render using React’s server rendering pipeline. This happens in two phases:</p>
</li>
</ol>
<ul>
<li><p><strong>Render to RSC Payload:</strong> React runs through the Server Components (layouts, page, and any nested Server Components) to produce a <strong>React Server Component Payload (RSC payload)</strong>. The RSC payload is a serialized binary format containing the rendered output of server components, plus <strong>placeholders for Client Components and references to their JS bundles</strong>. Essentially, it’s a description of the UI: HTML for server-rendered parts, and instructions for where client-rendered parts go.</p>
</li>
<li><p><strong>Generate HTML:</strong> Next.js then uses the RSC payload results along with the known client component boundaries to assemble the HTML for the response. Server Components’ output becomes HTML content, whereas each Client Component is left as a lightweight placeholder (often an empty container or loading hint) in the HTML. This HTML can be streamed to the browser (enabled by React Suspense boundaries), allowing the user to see partially rendered content sooner without waiting for all data to finish. At this stage, the server also includes scripts/tags to send the RSC payload to the client (for example, in a <code>&lt;script type="application/json"&gt;</code> or streaming over a network channel) so that the client-side React can pick it up.</p>
</li>
</ul>
<p>3. <strong>Server Response:</strong> The Next.js server returns the initial HTML along with the RSC payload (and the necessary JS bundles references for any client components). The HTML already contains the fully rendered UI of all Server Components (e.g. text, markup, etc.), so the user sees meaningful content on first paint. This HTML, however, is <strong>non-interactive</strong> at first — any buttons or client-side UI controls won’t yet respond.</p>
<p>4. <strong>Browser Rendering &amp; Static Content:</strong> The browser receives and parses the HTML. Immediately, it can display the server-rendered content. This gives a fast <em>First Contentful Paint</em> since no client-side code is needed yet to show the UI. At this point, the page looks complete but isn’t wired up to React on the client.</p>
<p><strong>5. Hydration Phase (Browser):</strong> In the background, the Next.js client runtime (hydration script) takes over. It loads the JavaScript for any <strong>Client Components</strong> that were included on the page (as referenced in the RSC payload). React on the client uses the RSC payload to <strong>reconcile the Server and Client Component trees</strong>, injecting the actual Client Component UI and state into the DOM where the placeholders were. Then <strong>hydration</strong> attaches event handlers and reactivates the interactive parts. Essentially:</p>
<ul>
<li><p>The RSC payload tells React what the server output was for each component, so React can create a virtual DOM tree matching it.</p>
</li>
<li><p>For each Client Component boundary, React will load its JS module and hydrate it: attach its event listeners, initialize state, etc. (using <code>ReactDOM.hydrateRoot</code>). Hydration makes the previously static HTML “live”.</p>
</li>
<li><p>All of this happens <em>concurrently</em>: while some Client Components hydrate, other parts of the page (Server Components) were already usable as static content, and any remaining streaming content can continue to load. React’s concurrency and Suspense allow hydration to be interleaved with any late-arriving chunks of the stream.</p>
</li>
</ul>
<p><strong>6. Interactive Page:</strong> Once hydration completes, the page is fully interactive. The user can now click buttons, use forms, open menus, etc. The initial load is now essentially a hydrated React app in the browser. Importantly, any purely server-rendered parts of the UI (Server Components without client logic) remain simply static DOM — they don’t incur additional JS overhead on the client beyond what’s needed to stitch them into React’s tree. Only the designated Client Components carry a client-side cost.</p>
<h3 id="heading-client-side-navigation-flow-app-router">Client-Side Navigation Flow (App Router)</h3>
<p>After the initial load, navigating between pages is typically done via <strong>client-side transitions</strong> (using <code>&lt;Link&gt;</code> or router APIs) to avoid full page reloads. The Next.js App Router handles these subsequent navigations efficiently:</p>
<ul>
<li><p>When the user clicks a Next <code>&lt;Link&gt;</code> to another route (e.g. from <code>/dashboard</code> to <code>/dashboard/profile</code>), the browser does <strong>not</strong> perform a traditional page refresh. Instead, the Next.js client intercepts the click and triggers a fetch to the server for the new route’s data. Specifically, Next will request the <strong>RSC payload</strong> for the new route (this is often an HTTP call to an internal API endpoint that returns the React Server Component payload for that page).</p>
</li>
<li><p>The Next.js <strong>Router</strong> on the client keeps a cache of previously fetched RSC payloads (the <strong>Router Cache</strong>). If the new route was preloaded or visited before, its RSC payload might already be cached, enabling near-instant navigation. (Next.js by default prefetches routes in the background when <code>&lt;Link&gt;</code> is in viewport, caching their RSC payload.)</p>
</li>
<li><p>The server generates the RSC payload for the new page (just like in initial load, but usually without needing to resend full HTML). This payload describes the portions of the UI that change. Because layouts can persist, Next.js will reuse any parent layout components that are common between the current page and the next page, and only fetch/render the segments that differ. For example, navigating between <code>/dashboard</code> and <code>/dashboard/profile</code> uses the same <code>app/layout.tsx</code> and <code>app/dashboard/layout.tsx</code>; those layouts stay mounted on the client. The server may only need to send the RSC payload for the <code>profile/page.tsx</code> content (and maybe a template, if present).</p>
</li>
<li><p>The browser receives the new RSC payload (as JSON or binary data). React then <strong>merges the new server-rendered content into the existing DOM</strong>. This is done by computing the differences between the current UI and the new one, based on the RSC payload. React will update the DOM to reflect the new page — injecting, updating, or removing elements as needed. Crucially, this happens <strong>without unloading the JavaScript environment</strong>: the React app remains running, so any state in persistent layouts or already-mounted client components can be preserved.</p>
</li>
<li><p>Any new Client Components required by the navigation will be loaded and hydrated as part of this process. Since no full page reload occurred, the already-mounted Client Components in parent layouts remain live (they do not re-mount). Any Client Components that are no longer needed (from the previous page) will be unmounted, and new ones will be initialized.</p>
</li>
<li><p>The result is a seamless SPA-like transition. Next.js also supports <strong>streaming in new content</strong> during navigation: you can use React Suspense boundaries with <code>loading.tsx</code> in App Router to show a fallback UI while waiting for the new content to load. The RSC payload can stream, so pieces of the new page can progressively fill in. This provides a smooth UX for navigation, even if some data is slightly delayed.</p>
</li>
</ul>
<p>In summary, <strong>subsequent navigations</strong> fetch and apply an RSC payload instead of a full document, using cached data when possible. According to Next.js: *“On subsequent navigations, the RSC Payload is prefetched and cached for instant navigation, and Client Components are rendered entirely on the client, without the server-rendered HTML.”*This means after first load, pages update via client-side React rather than a full SSR roundtrip (though the server still provides fresh data through RSC). The App Router intelligently <strong>preserves layout state</strong> (thanks to layouts not unmounting) and only changes what’s necessary, enabling fast transitions.</p>
<h3 id="heading-data-fetching-and-built-in-optimizations">Data Fetching and Built-In Optimizations</h3>
<p>Next.js v15 provides powerful <strong>built-in data fetching mechanisms</strong> that integrate with the RSC architecture:</p>
<ul>
<li><p><strong>Async Server Components with</strong> <code>fetch</code><strong>:</strong> In the App Router, you can fetch data directly inside a Server Component by making the component <code>async</code> and using the Web <code>fetch()</code> API (or any async call). For example, you can <code>await fetch('https://...')</code> at the top of a <code>page.tsx</code> component to retrieve data on the server. This removes the need for separate data fetching methods (like getServerSideProps) – data is co-located with the component. Next.js extends the <code>fetch</code> API to improve performance: <strong>by default, fetch calls are automatically cached and deduplicated</strong> during the rendering process. If the same request URL is called multiple times in a single request (say in a layout and a page), Next.js will perform it once and reuse the result, avoiding duplicate work. This is often called <em>request memoization</em> – React 18 handles it under the hood for GET requests. By default, Next.js will cache fetch responses indefinitely when possible (during build for static props, or in-memory on the server between requests if not opted out). You can customize this with fetch options:</p>
</li>
<li><p><code>fetch(url, { cache: 'force-cache' })</code>: uses Next.js <strong>Data Cache</strong> – serve cached data if available (fresh) or fetch and then cache it.</p>
</li>
<li><p><code>fetch(url, { cache: 'no-store' })</code>: always fetch fresh data (no caching).</p>
</li>
<li><p><code>fetch(url, { next: { revalidate: 10 } })</code>: set a time-based revalidation (stale-while-revalidate) in seconds. This controls how long a cached response is considered fresh. Setting <code>revalidate: 0</code> is equivalent to <code>no-store</code> (no caching).</p>
</li>
<li><p>By using these options or environment (development vs production), Next.js allows both <strong>static caching</strong> (during build) and <strong>dynamic data fetching</strong> where needed. The default for most Server Components is to <strong>statically pre-render and cache</strong> the data on first request, unless you mark it dynamic. <em>(Good to know: In development, caching is usually disabled so that fetch always runs, to ease debugging.)</em></p>
</li>
<li><p><code>React.cache()</code> <strong>utility:</strong> Not all data fetching goes through <code>fetch</code>. If you are querying a database via an ORM, or using a third-party SDK (which might not use fetch under the hood), you can still benefit from deduplication. React provides a <code>cache()</code> function (in React 18+) to memoize any async function on a per-request basis. For instance, you can wrap your DB query function: <code>const getProducts = cache(async () =&gt; db.findAll())</code>. When called multiple times during the rendering of a single page, the cached version ensures the actual operation runs only once. Next.js recommends using <code>fetch</code> (which is auto-memoized) when possible, or <code>cache()</code> for custom data functions, to avoid duplicate data fetching in layouts and pages. This fits the App Router’s pattern of fetching in multiple components without lifting all data up to a single load – you simply fetch where needed and trust the framework to avoid unnecessary network calls.</p>
</li>
<li><p><code>server-only</code> <strong>and</strong> <code>client-only</code><strong>:</strong> Next.js provides special packages to enforce separation of concerns. If you have a module that should <strong>only run on the server</strong> (e.g. it contains secret keys or Node-only code), you can import <code>'server-only'</code> at the top of it. This will cause Next to throw a build error if that module is ever imported into a Client Component (preventing accidental leakage of server code to the client). Conversely, a <code>'client-only'</code> package exists to mark modules that should only run in the browser (e.g. rely on <code>window</code>). These safeguards help catch mistakes where you might import something like a database client into a Client Component. Next.js already automatically strips out most server-only code from client bundles (e.g. <code>process.env</code> without <code>NEXT_PUBLIC</code> will be an empty string on client), but using <code>server-only</code> gives an explicit guarantee and clearer error messages.</p>
</li>
<li><p><strong>React’s</strong> <code>use()</code> <strong>Hook for Streaming:</strong> A new addition as of React 18/Next 15 is the <code>use()</code> hook, which allows a Client Component to consume an async resource (like a Promise) directly <em>during rendering</em>. Next.js uses this to enable <strong>streaming SSR with partial hydration</strong>. The typical pattern is: a Server Component kicks off a data fetch without awaiting it, and passes the Promise down to a Client Component via a prop. The Client Component, being wrapped in a <code>&lt;Suspense&gt;</code> boundary, calls <code>use(promise)</code> to read the result of that async call. React will suspend rendering of that Client Component until the promise resolves, allowing the server to stream the rest of the content and the client to show a fallback UI. Once the promise resolves (data is ready), the Client Component will hydrate with the real data. This mechanism essentially lets you <em>split</em> data fetching: fetch on the server, but defer consuming it to the client at render-time, which is useful for cases where you need client-side interactivity with server-fetched data. It’s an advanced technique, but it’s <strong>built-in</strong> with the App Router (no need for state management libraries just to bridge server-&gt;client data).</p>
</li>
<li><p><strong>Progressive Hydration and Streaming:</strong> The App Router’s architecture inherently supports streaming and selective hydration. Using <code>&lt;Suspense&gt;</code> boundaries and special files like <code>loading.tsx</code>, you can create <strong>skeleton UIs or spinners</strong> that show instantly while deeper parts of the page load data. Next.js will stream HTML in chunks for each Suspense boundary that resolves, and hydrate components as they arrive. Hydration is also <strong>selective</strong>: only Client Components need hydration, and they can hydrate independently. For example, a slow, large Client Component can be wrapped in Suspense so that other interactive components on the page hydrate sooner, without waiting for the slow one. This fine-grained control is a direct benefit of RSC and the App Router.</p>
</li>
</ul>
<h3 id="heading-terminology-mapping">Terminology Mapping</h3>
<p><strong>Next.js v15 App Router</strong> introduces a paradigm where the <strong>server is deeply involved in rendering React components</strong>, while the client takes on hydration and navigation responsibilities. The above architecture can be summarized by the flow of data and control:</p>
<ul>
<li><p><strong>Browser -&gt; Server:</strong> Requests a route; Next.js server constructs the React tree (Layouts, Templates, Page) and renders to HTML + RSC payload.</p>
</li>
<li><p><strong>Server -&gt; Browser:</strong> Sends down HTML (UI markup) and RSC payload (serialized component tree data) in the response.</p>
</li>
<li><p><strong>Browser (React client):</strong> Immediately displays HTML, then uses the RSC payload to load/hydrate Client Components and attach event handlers (hydration).</p>
</li>
<li><p><strong>User Interaction / Subsequent Route Change:</strong> Next.js fetches new RSC payload (using built-in caching for speed) and updates the client-side React state, reusing persistent Layouts and rehydrating new parts. No full page reload occurs.</p>
</li>
</ul>
<p>All of this is achieved with <strong>no third-party state libraries or client-side routers</strong> — just Next.js’s built-in capabilities and React’s advancements. By understanding the roles of <strong>Server Components vs Client Components</strong>, and how <strong>Layouts</strong> persist while <strong>Templates</strong> can reset state on navigation, you can architect a Next.js app that is both <strong>high-performance</strong> (minimal client JS, efficient data fetching) and <strong>highly dynamic</strong> (rich interactions via hydration). Next.js v15’s App Router provides a robust foundation out of the box to handle routing, data fetching, caching, and rendering in a unified, developer-friendly way.</p>
<h2 id="heading-how-to-client-side-render-a-component-in-nextjs">How to Client-Side-Render a Component in Next.js</h2>
<p>Whether something in Next.js is client-side or server-side rendered can be easily determined. We will work with this simple component:</p>
<pre><code class="lang-javascript">&lt;&gt;
  <span class="xml"><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></span>
&lt;/&gt;
</code></pre>
<p>Using Next.js’ default server-side rendering, the generated HTML looks like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734517110669/678d2144-179c-4505-a08d-89991e3b13c9.webp" alt class="image--center mx-auto" /></p>
<p>You can see the component’s XML is rendered on the server.</p>
<p>Meanwhile, using client-side rendering, the initial HTML response looks like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734517211964/25d7cc6d-abe6-404f-8ee4-7292376f4303.webp" alt class="image--center mx-auto" /></p>
<p>Of course, the “Hello World!“ still appears in the DOM, but it takes some time because it is rendered through client-side JavaScript.</p>
<p>Here are 3 ways to achieve CSR in Next.js:</p>
<h3 id="heading-method-1-timing-with-useeffect">Method 1: Timing with <code>useEffect</code></h3>
<p>If you use Next.js’s new App Router, every component is a server component by default and can’t use React hooks. Therefore, we declare it as a client component on top by stating <code>“use client“</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-string">'use client'</span>
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Index</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isMounted, setIsMounted] = useState(<span class="hljs-literal">false</span>)

  useEffect(<span class="hljs-function">() =&gt;</span> {
    setIsMounted(<span class="hljs-literal">true</span>)
  }, [])

  <span class="hljs-keyword">if</span> (!isMounted) {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <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>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  )
}
</code></pre>
<h3 id="heading-method-2-dynamic-components">Method 2: Dynamic components</h3>
<p>Using a dynamic import, a component can also be rendered only on the client side. The reason is simple: The component is imported once the wrapping component is rendered; therefore, all the work is happening on the client.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>

<span class="hljs-keyword">const</span> HelloWorld = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/HelloWorld'</span>), {
  <span class="hljs-attr">ssr</span>: <span class="hljs-literal">false</span>,
})

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Index</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">HelloWorld</span> /&gt;</span></span>
}
</code></pre>
<p>This approach works both for clients and for server-side components.</p>
<h3 id="heading-method-3-use-the-window-object-only-pages-router">Method 3: Use the window object (Only Pages Router)</h3>
<blockquote>
<p>Hint: This approach doesn’t work in the new App Router</p>
</blockquote>
<p>This trick is so simple: When we render something on the server, the window object isn’t available in our code. Why? Well, because the window object is exclusive to the browser, of course.</p>
<p>Since we can access this special object in Next.js, we check if we are on the server or not. Therefore, we can save if server-side rendering is happening in a variable like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> SSR = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> === <span class="hljs-string">'undefined'</span>
</code></pre>
<p>SSR is true if server-side rendering of our JSX is happening. To only client-side render something, use this variable:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> SSR = <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">window</span> == <span class="hljs-string">'undefined'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Index</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;&gt;</span>{!SSR ? <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> : null}<span class="hljs-tag">&lt;/&gt;</span></span>
}
</code></pre>
<h2 id="heading-nextjs-middleware-the-secret-weapon-every-developer-should-use">Next.js Middleware — The Secret Weapon Every Developer Should Use</h2>
<p>When building modern web apps with Next.js, there are times when you need to run code before a request is completed — for authentication, logging, redirects, security, or personalization.</p>
<p>That’s where <strong>Next.js Middleware</strong> comes in.</p>
<blockquote>
<p>It’s like a <strong>bouncer at a club</strong> 🕶️ — checking requests <strong>before</strong> they enter your pages.</p>
</blockquote>
<h3 id="heading-what-is-the-middleware-in-nextjs">What is the middleware in Next.js?</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758273346671/96aabf28-b3b5-4fcd-8a14-db5683a8fcbd.webp" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Middleware in Next.js is a <strong>function that runs before a request is completed</strong>.</p>
</li>
<li><p>Think of it like a <strong>gatekeeper</strong> — it runs before the page is rendered.</p>
</li>
<li><p>It runs on the <strong>Edge</strong>, meaning it’s super fast (close to the user geographically).</p>
</li>
<li><p>It lets you <strong>modify requests and responses</strong>, <strong>redirect</strong>, <strong>rewrite paths</strong>, and more — without a full server.</p>
</li>
</ul>
<p>📁 Middleware is created in a special file:</p>
<pre><code class="lang-typescript">/middleware.ts or /middleware.js
</code></pre>
<h3 id="heading-use-case-1-authentication-check-protected-routes">Use Case #1: Authentication Check (Protected Routes)</h3>
<p>Let’s say you have pages like <code>/dashboard</code>, <code>/profile</code>, or <code>/admin</code>.<br />You don’t want unauthenticated users accessing them.</p>
<p><strong>Here’s how you can restrict access using middleware:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// middleware.ts</span>
<span class="hljs-keyword">import</span> { NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">request: NextRequest</span>) </span>{
  <span class="hljs-keyword">const</span> token = request.cookies.get(<span class="hljs-string">'token'</span>)?.value;
  <span class="hljs-comment">// Protect these routes</span>
  <span class="hljs-keyword">const</span> protectedRoutes = [<span class="hljs-string">'/dashboard'</span>, <span class="hljs-string">'/profile'</span>, <span class="hljs-string">'/admin'</span>];
  <span class="hljs-keyword">if</span> (protectedRoutes.includes(request.nextUrl.pathname)) {
    <span class="hljs-keyword">if</span> (!token) {
      <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/login'</span>, request.url));
    }
  }
  <span class="hljs-keyword">return</span> NextResponse.next();
}
</code></pre>
<p>✅ <strong>Why this works:</strong></p>
<ul>
<li><p>Middleware reads the token from cookies (set when the user logs in).</p>
</li>
<li><p>If it’s missing and the user tries to visit a protected route, they get redirected to <code>/login</code>.</p>
</li>
</ul>
<h3 id="heading-use-case-2-locale-based-redirects-geo-redirects">Use Case #2: Locale-Based Redirects (Geo Redirects)</h3>
<p>Imagine your site supports English and Spanish users, and you want to auto-redirect based on their location or headers.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// middleware.ts</span>
<span class="hljs-keyword">import</span> { NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">request: NextRequest</span>) </span>{
  <span class="hljs-keyword">const</span> { nextUrl, headers } = request;
  <span class="hljs-keyword">const</span> country = headers.get(<span class="hljs-string">'x-vercel-ip-country'</span>) || <span class="hljs-string">'US'</span>;
  <span class="hljs-keyword">if</span> (nextUrl.pathname === <span class="hljs-string">'/'</span>) {
    <span class="hljs-keyword">if</span> (country === <span class="hljs-string">'ES'</span>) {
      <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/es'</span>, request.url));
    }
    <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/en'</span>, request.url));
  }
  <span class="hljs-keyword">return</span> NextResponse.next();
}
</code></pre>
<p>✅ <strong>Bonus Tip:</strong><br />If you deploy on <strong>Vercel</strong>, the <code>x-vercel-ip-country</code> header comes built-in!<br />You don’t need to manually detect IPs or use third-party services.</p>
<h3 id="heading-use-case-3-logging-or-analytics">Use Case #3: Logging or Analytics</h3>
<p>Need to track page visits, log IPs, or count hits per route?</p>
<p>Middleware is perfect for this since it runs <em>before</em> anything renders.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// middleware.ts</span>
<span class="hljs-keyword">import</span> { NextRequest } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">request: NextRequest</span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`[Page Visit] <span class="hljs-subst">${request.nextUrl.pathname}</span> from IP: <span class="hljs-subst">${request.ip}</span>`</span>);
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-literal">null</span>, { status: <span class="hljs-number">204</span> }); <span class="hljs-comment">// Or just: return NextResponse.next();</span>
}
</code></pre>
<p>✅ <strong>When to use this:</strong></p>
<ul>
<li><p>Custom logging</p>
</li>
<li><p>Tracking traffic patterns</p>
</li>
<li><p>Counting route visits without adding client-side JS</p>
</li>
</ul>
<p>📌 <strong>Pro Tip:</strong> Instead of <code>console.log</code>, sending logs to services like Logtail, Sentry, or even your own API.</p>
<h3 id="heading-middleware-matchers-optional-filtering">Middleware Matchers (Optional Filtering)</h3>
<p>Don’t want your middleware to run on <strong>every</strong> request?</p>
<p>Use matchers!</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// middleware.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  matcher: [<span class="hljs-string">'/dashboard/:path*'</span>, <span class="hljs-string">'/profile'</span>, <span class="hljs-string">'/admin'</span>],
};
</code></pre>
<p>This makes your middleware run <strong>only</strong> for these routes.</p>
<h3 id="heading-limitations">Limitations</h3>
<ul>
<li><p>Runs <strong>before</strong> the cache layer (so can’t directly use server actions).</p>
</li>
<li><p>No access to React state or hooks (it’s not in the React tree).</p>
</li>
<li><p>Designed for <strong>lightweight logic</strong>, not heavy data fetching.</p>
</li>
</ul>
<h2 id="heading-when-to-use-react-query-with-nextjs-server-components">When To Use React Query With Next.js Server Components</h2>
<p>React Server Components have revolutionized how we think about data fetching in React applications. But what happens when you want to use React Query alongside server components? Should we always combine them? The answer might surprise you.</p>
<p>With React now running on both client and server, developers are grappling with how traditional client-side libraries like React Query fit into this new paradigm. The reality is more nuanced than simply “use both everywhere“.</p>
<h3 id="heading-setting-up-react-query-for-server-components">Setting up React Query for Server Components</h3>
<p>The foundation of using React Query with server components lies in proper setup. Here’s a key pattern:</p>
<p><strong>The Query Client Factory</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { isServer, QueryClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeQueryClient</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> QueryClient({
    defaultOptions: {
      queries: {
        staleTime: <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>, <span class="hljs-comment">// 1 minute</span>
      },
    },
  });
}

<span class="hljs-keyword">let</span> browserQueryClient: QueryClient | <span class="hljs-literal">undefined</span> = <span class="hljs-literal">undefined</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getQueryClient</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">if</span> (isServer) {
    <span class="hljs-comment">// Always create a new query client on the server</span>
    <span class="hljs-keyword">return</span> makeQueryClient();
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Create a singleton on the client</span>
    <span class="hljs-keyword">if</span> (!browserQueryClient) {
      browserQueryClient = makeQueryClient();
    }
    <span class="hljs-keyword">return</span> browserQueryClient;
  }
}
</code></pre>
<p><strong>Why This Pattern Matters</strong></p>
<p>The server-client distinction is crucial:</p>
<ul>
<li><p>Server: Always create a new query client instance for each request to avoid data leakage between users.</p>
</li>
<li><p>Client: Maintain a singleton to persist across component re-renders and suspend boundaries.</p>
</li>
</ul>
<p>This pattern is especially important in Next.js, where the layout component is wrapped in a Suspense boundary behind the scenes. Without the singleton pattern, you would lose your client instance every time a component suspends.</p>
<h3 id="heading-the-server-client-data-flow">The Server-Client Data Flow</h3>
<p>Here’s how data flows from server to client:</p>
<p><strong>1. Server Component (Prefetching)</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// posts/page.tsx - Server Component</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PostsPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> queryClient = getQueryClient();

  <span class="hljs-comment">// Prefetch data on the server</span>
  <span class="hljs-keyword">await</span> queryClient.prefetchQuery({
    queryKey: [<span class="hljs-string">'posts'</span>],
    queryFn: getPosts,
  });

<span class="hljs-keyword">return</span> (
    &lt;HydrationBoundary state={dehydrate(queryClient)}&gt;
      &lt;PostsClient /&gt;
    &lt;/HydrationBoundary&gt;
  );
}
</code></pre>
<p><strong>2. Client Component (Consumption)</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// PostsClient.tsx - Client Component</span>
<span class="hljs-string">'use client'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PostsClient</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data: posts } = useQuery({
    queryKey: [<span class="hljs-string">'posts'</span>],
    queryFn: getPosts,
  });
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {posts?.map(<span class="hljs-function"><span class="hljs-params">post</span> =&gt;</span> (
        &lt;div key={post.id}&gt;{post.title}&lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
}
</code></pre>
<p><strong>3. The Hydration Bridge</strong></p>
<p>The <code>HydrationBoundary</code> component bridges the server and client by:</p>
<ul>
<li><p>Dehydrating the query client state on the server</p>
</li>
<li><p>Rehydrating it on the client</p>
</li>
<li><p>Making prefetched data immediately available</p>
</li>
</ul>
<p><strong>This Is Actually Good!</strong></p>
<ol>
<li><p>Data is prefetched on the server</p>
</li>
<li><p>Hydrated to the client without additional network requests</p>
</li>
<li><p>The user sees data immediately without loading states</p>
</li>
</ol>
<p>This is exactly what makes React Query with Next.js so powerful — you get server-side rendering with client-side cache management, giving you the best of both worlds for performance and user experience.</p>
<p><strong>What Not To Do</strong></p>
<p>A common mistake is fetching data in server components and trying to use it directly:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ❌ Don't do this</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PostsPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> queryClient = getQueryClient();
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> queryClient.fetchQuery({
    queryKey: [<span class="hljs-string">'posts'</span>],
    queryFn: getPosts,
  });

  <span class="hljs-keyword">return</span> &lt;PostsClient posts={posts} /&gt;;
}
</code></pre>
<p><strong>Why this breaks:</strong> Server components don’t re-render. If the client-side query cache gets invalidated or updated, your server component will display stale data, creating UI inconsistencies.</p>
<h3 id="heading-why-doesnt-the-client-refresh-data-on-the-first-load">Why doesn’t the client refresh data on the first load?</h3>
<p>When using React Query with Next.js Server Components, something important happens behind the scenes during the initial page load.</p>
<p>First, your server component <strong>fetches the data</strong> ahead of time using React Query’s prefetchQuery. This means the server already has the data ready before sending the page to the browser.</p>
<p>Then, using the &lt;HydrationBoundary&gt;, this prefetched data is <strong>passed down to the client</strong>, so React Query on the client side starts with a <strong>fully populated cache</strong>.</p>
<p>Because the data is already available and considered fresh, React Query doesn’t make a new network request when the page loads in the browser. It simply reads from the cache. This improves performance and avoids unnecessary data fetching.</p>
<p>However, if you change a filter or the query becomes stale, React Query will then fetch new data as needed.</p>
<p>This setup allows you to:</p>
<ul>
<li><p>Render data instantly on first load</p>
</li>
<li><p>Avoid duplicate fetching</p>
</li>
<li><p>Keep the client-side declarative (using useQuery)</p>
</li>
<li><p>Maintain a clean separation between server and client responsibilities</p>
</li>
</ul>
<p>In short, the server does the heavy lifting up front, and the client reuses that work efficiently.</p>
<h3 id="heading-when-to-use-react-query-with-server-components">When to Use React Query with Server Components</h3>
<p>React Query with server components makes sense when you need:</p>
<p><strong>1. Client-Specific Features</strong></p>
<p><strong>Infinite Queries</strong> for pagination and infinite scroll:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Server prefetch</span>
<span class="hljs-keyword">await</span> queryClient.prefetchInfiniteQuery({
  queryKey: [<span class="hljs-string">'posts'</span>],
  queryFn: <span class="hljs-function">(<span class="hljs-params">{ pageParam = <span class="hljs-number">1</span> }</span>) =&gt;</span> getPosts(pageParam),
});

<span class="hljs-comment">// Client usage</span>
<span class="hljs-keyword">const</span> { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
  queryKey: [<span class="hljs-string">'posts'</span>],
  queryFn: <span class="hljs-function">(<span class="hljs-params">{ pageParam = <span class="hljs-number">1</span> }</span>) =&gt;</span> getPosts(pageParam),
  getNextPageParam: <span class="hljs-function">(<span class="hljs-params">lastPage</span>) =&gt;</span> lastPage.nextPage,
});
</code></pre>
<p><strong>2. Real-time Updates</strong></p>
<p>When you need optimistic updates, cache invalidation, or real-time synchronization across components.</p>
<p><strong>3. Complex State Management</strong></p>
<p>For applications requiring sophisticated caching strategies, background refetching, or retry logic.</p>
<p>**When to Skip React Query<br />**Often, you’re better off with pure server components:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Simple and effective</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PostsPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> getPosts();

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {posts.map(<span class="hljs-function"><span class="hljs-params">post</span> =&gt;</span> (
        &lt;PostCard key={post.id} post={post} /&gt;
      ))}
    &lt;/div&gt;
  );
}
</code></pre>
<p>This approach offers:</p>
<ul>
<li><p><strong>Better performance</strong>: No JavaScript bundle for data fetching</p>
</li>
<li><p><strong>Simpler architecture</strong>: Fewer moving parts</p>
</li>
<li><p><strong>Better SEO</strong>: Content rendered on the server</p>
</li>
<li><p><strong>Faster initial load</strong>: No client-side fetching delay</p>
</li>
</ul>
<p><strong>Making the Right Choice</strong></p>
<p>Consider these questions:</p>
<ol>
<li><p><strong>Do you need client-side interactivity</strong> like infinite scroll, real-time updates, or optimistic mutations?</p>
</li>
<li><p><strong>Is your data relatively static</strong> or does it change frequently?</p>
</li>
<li><p><strong>Do you need complex caching strategies</strong> or is simple server-side fetching sufficient?</p>
</li>
<li><p><strong>Are you building a highly interactive app</strong> or primarily displaying content?</p>
</li>
</ol>
<h3 id="heading-best-practices">Best Practices</h3>
<p><strong>1. Start Simple</strong></p>
<p>Begin with pure server components. Add React Query only when you need client-specific features.</p>
<p><strong>2. Use Appropriate Stale Times</strong></p>
<p>Set longer stale times when prefetching to avoid immediate refetches:</p>
<pre><code class="lang-typescript">defaultOptions: {
  queries: {
    staleTime: <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>, <span class="hljs-comment">// Prevent immediate refetch after prefetch</span>
  },
}
</code></pre>
<p><strong>3. Separate Concerns</strong></p>
<p>Keep your client components unaware of server prefetching. They should work independently.</p>
<p><strong>4. Consider Bundle Size</strong></p>
<p>React Query adds to your JavaScript bundle. Ensure the benefits outweigh the costs.</p>
<h3 id="heading-real-world-use-cases">Real-world use cases</h3>
<p><strong>Example 1: Basic Query — Filter-based query caching</strong></p>
<p>This example demonstrates React Query’s fundamental capabilities with Next.js App Router. It showcases:</p>
<ul>
<li><p>Server-side prefetching that hydrates the client cache on initial load</p>
</li>
<li><p>Filter-based query keys that maintain separate cache entries per filter</p>
</li>
<li><p>Automatic cache invalidation after the configured stale time (60 seconds)</p>
</li>
<li><p>Clean separation between server and client components</p>
</li>
</ul>
<p>The UI displays a collection of shoes that can be filtered by category. When users switch filters, you can observe React Query’s intelligent caching, only fetching new data when needed, while serving cached data instantly.</p>
<p><strong>Example 2: Infinite Query — Infinite scroll with pagination</strong></p>
<p>This example showcases React Query’s advanced infinite scrolling capabilities. Key features include:</p>
<ul>
<li><p>Implementation of useInfiniteQuery for paginated data loading</p>
</li>
<li><p>Automatic loading of the next pages as the user scrolls to the bottom</p>
</li>
<li><p>Server-side prefetching of the initial data page with prefetchInfiniteQuery</p>
</li>
<li><p>Cursor-based pagination handling a dataset of 100 items in batches of 10</p>
</li>
<li><p>Intersection Observer integration for detecting when to load more data</p>
</li>
</ul>
<p>The UI demonstrates a real-world infinite scroll implementation with loading indicators and smooth state transitions, all while maintaining the benefits of React Query’s caching system.</p>
<p>These examples together provide a comprehensive look at how React Query integrates with Next.js to solve common data fetching challenges.</p>
<h2 id="heading-5-nextjs-image-pitfalls-that-hurt-performance">5 Next.js Image Pitfalls That Hurt Performance</h2>
<p>Last month, I watched my e-commerce product page from a decent load time to a painful 4.2 seconds after implementing Next.js Image across our dynamic product catalog. Our bounce rate spiked, customers abandoned carts, and I realized something brutal: the “Image Component“ was destroying my site’s performance. After weeks of debugging slow load times, failed builds, and frustrated users, I discovered that sometimes the optimization creates more problems than it solves.</p>
<p>While working on the e-commerce website using Next.js 14, I learned the hard way that the Next.js Image Component isn’t always the performance hero it meant to be. After switching to targeted alternatives to our dynamic images from third-party APIs, I cut out product pages’ load times from 4.2 seconds to 1.8 seconds — a 57% improvement that saved our conversion rate.</p>
<p>Don’t get me wrong — the Next.js Image Component is powerful. It automatically handles lazy loading, WebP conversion, responsive sizing, and more. But if you are dealing with dynamic image sources, high-volume image pages, or mysterious performance bottlenecks, this section might save you weeks of headaches like it did for me.</p>
<h3 id="heading-understanding-nextjs-image-component-and-its-hidden-cost">Understanding Next.js Image Component (And Its Hidden Cost)</h3>
<p>The Next.js Image Component promises seamless image optimizations through features like:</p>
<ul>
<li><p><strong>Automatic format conversion</strong> (WebP, AVIF)</p>
</li>
<li><p><strong>Lazy loading</strong> with Intersection Observer</p>
</li>
<li><p><strong>Responsive sizing</strong> with srcset generation</p>
</li>
<li><p><strong>Blur placeholder</strong> support</p>
</li>
<li><p><strong>Priority loading</strong> for above-the-fold images</p>
</li>
</ul>
<p>Under the hood, Next.js Images rely on either Vercel’s Image Optimization API (in production) or the Sharp library (for local development and self-hosted deployments). This means every image gets processed on-demand, which sounds great in theory.</p>
<p>The reality? On-demand optimization can become a performance bottleneck, especially when dealing with unpredictable image sources or high-traffic scenarios. Here’s when that “optimization“ starts working against you.</p>
<h3 id="heading-5-key-scenarios-when-you-should-not-use-nextjs-image">5 Key Scenarios When You Should Not Use Next.js Image</h3>
<p><strong>1. Dynamic Image Sources from Third-Party APIs</strong></p>
<p><strong>The Problem:</strong> This is the big one that hit my e-commerce site hard. When your images come from external APIs with unpredictable URLs, domains, or formats, Next.js Image becomes a liability rather than an asset.</p>
<p><strong>Real-World Example:</strong> Our product catalog pulls images from a supplier’s API. These images come from random CDN domains, vary in size and format, and change frequently. Here’s what happens with Next.js Image.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// This creates a bottleneck</span>
&lt;Image 
  src={<span class="hljs-string">`https://random-supplier-cdn-<span class="hljs-subst">${<span class="hljs-built_in">Math</span>.random()}</span>.com/product-<span class="hljs-subst">${id}</span>.jpg`</span>}
  alt=<span class="hljs-string">"Product image"</span>
  width={<span class="hljs-number">500</span>}
  height={<span class="hljs-number">500</span>}
/&gt;
</code></pre>
<p><strong>What Goes Wrong:</strong></p>
<ul>
<li><p><strong>Domain Configuration Nightmare:</strong> Next.js 14 requires pre-configuring image domains in <code>next.config.js</code>. With dynamic third-party sources, this becomes impossible to maintain.</p>
</li>
<li><p><strong>Runtime Processing Delays:</strong> Each new image URL triggers real-time optimization, adding 2–3 seconds to initial load times.</p>
</li>
<li><p><strong>404 Errors:</strong> Unconfigured domains default to broken images or fallback behavior.</p>
</li>
</ul>
<p><strong>The Better Solution:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Direct img tag with external CDN optimization</span>
&lt;img 
  src={<span class="hljs-string">`https://your-cdn.com/optimize?url=<span class="hljs-subst">${<span class="hljs-built_in">encodeURIComponent</span>(dynamicImageUrl)}</span>&amp;w=500&amp;q=80`</span>}
  alt=<span class="hljs-string">"Product image"</span>
  loading=<span class="hljs-string">"lazy"</span>
  style={{ width: <span class="hljs-string">'100%'</span>, height: <span class="hljs-string">'auto'</span> }}
/&gt;
</code></pre>
<p><strong>Performance Impact:</strong> After switching to direct <code>&lt;img&gt;</code> tags with Cloudinary URL transformations, our product page load times dropped from 4.2 seconds to 1.8 seconds.</p>
<p><strong>2. High-Volume Image Pages (Product Grids, Galleries)</strong></p>
<p><strong>The Problem:</strong> Pages displaying dozens or hundreds of images simultaneously can overwhelm Next.js Image’s optimization pipeline.</p>
<p><strong>Real-World Example:</strong> Our category pages show 48 products per page. With Next.js Image, the browser attempts to optimize multiple images simultaneously, creating a processing queue that delays the entire page render.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// This kills performance on high-volume pages</span>
{products.map(<span class="hljs-function"><span class="hljs-params">product</span> =&gt;</span> (
  &lt;Image 
    key={product.id}
    src={product.imageUrl}
    alt={product.name}
    width={<span class="hljs-number">300</span>}
    height={<span class="hljs-number">300</span>}
  /&gt;
))}
</code></pre>
<p><strong>What Goes Wrong:</strong></p>
<ul>
<li><p><strong>Server Overload:</strong> Each image optimization request consumes server resources</p>
</li>
<li><p><strong>Concurrent Processing Limits:</strong> Most hosting platforms limit simultaneous image processing</p>
</li>
<li><p><strong>Waterfall Loading:</strong> Images load sequentially rather than in parallel</p>
</li>
<li><p><strong>Cost Implications:</strong> Vercel’s Image Optimization API charges per optimization request</p>
</li>
</ul>
<p><strong>The Better Solution:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Pre-optimized images with native lazy loading</span>
{products.map(<span class="hljs-function"><span class="hljs-params">product</span> =&gt;</span> (
  &lt;img 
    key={product.id}
    src={<span class="hljs-string">`<span class="hljs-subst">${product.optimizedImageUrl}</span>?w=300&amp;h=300&amp;fit=crop`</span>}
    alt={product.name}
    loading=<span class="hljs-string">"lazy"</span>
    style={{ aspectRatio: <span class="hljs-string">'1/1'</span>, objectFit: <span class="hljs-string">'cover'</span> }}
  /&gt;
))}
</code></pre>
<p><strong>Performance Impact:</strong> Moving to pre-optimized CDN images reduced our category page Largest Contentful Paint (LCP) from 3.4s to 1.2s.</p>
<p><strong>3. Unsupported or Unpredictable Image Domains</strong></p>
<p><strong>The Problem:</strong> Next.js Image’s security model requires explicit domain configuration, but modern applications often work with dynamic or user-generated content from unknown sources.</p>
<p><strong>Real-World Example:</strong> Our platform allows users to upload images or import from social media. These images come from countless domains we can’t predict or pre-configure.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// next.config.js becomes unmaintainable</span>
<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  images: {
    domains: [
      <span class="hljs-string">'cdn1.example.com'</span>,
      <span class="hljs-string">'cdn2.example.com'</span>,
      <span class="hljs-string">'user-uploads.s3.amazonaws.com'</span>,
      <span class="hljs-string">'instagram.com'</span>,
      <span class="hljs-string">'facebook.com'</span>,
      <span class="hljs-comment">// ... hundreds more?</span>
    ],
  },
}
</code></pre>
<p><strong>What Goes Wrong:</strong></p>
<ul>
<li><p><strong>Maintenance Hell:</strong> Constantly updating domain configurations</p>
</li>
<li><p><strong>Security Concerns:</strong> Wildcard domains create vulnerabilities</p>
</li>
<li><p><strong>Build Failures:</strong> Invalid or inaccessible domains break deployments</p>
</li>
<li><p><strong>User Experience:</strong> Broken images when domains aren’t configured</p>
</li>
</ul>
<p><strong>The Better Solution:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Proxy through your own domain or use unrestricted img tags</span>
<span class="hljs-keyword">const</span> ProxiedImage = <span class="hljs-function">(<span class="hljs-params">{ src, alt, ...props }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> proxiedSrc = <span class="hljs-string">`/api/image-proxy?url=<span class="hljs-subst">${<span class="hljs-built_in">encodeURIComponent</span>(src)}</span>`</span>;
  <span class="hljs-keyword">return</span> &lt;img src={proxiedSrc} alt={alt} loading=<span class="hljs-string">"lazy"</span> {...props} /&gt;;
};
</code></pre>
<p><strong>4. Custom Optimization Requirements</strong></p>
<p><strong>The Problem:</strong> Next.js Image applies default optimization settings that might not suit specialized use cases like high-resolution product zoom, medical imaging, or artistic portfolios.</p>
<p><strong>Real-World Example:</strong> Our drop-shipping e-commerce site needs pixel-perfect product zoom functionality. Customers expect to see every detail, but Next.js Image’s default 75% quality compression destroys the fine details.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Default optimization destroys image quality</span>
&lt;Image 
  src=<span class="hljs-string">"/diamond-ring-4k.jpg"</span>
  alt=<span class="hljs-string">"Diamond ring detail"</span>
  width={<span class="hljs-number">2000</span>}
  height={<span class="hljs-number">2000</span>}
  quality={<span class="hljs-number">75</span>} <span class="hljs-comment">// Not enough for detailed zoom</span>
/&gt;
</code></pre>
<p><strong>What Goes Wrong:</strong></p>
<ul>
<li><p><strong>Quality Loss:</strong> Default compression settings reduce image fidelity</p>
</li>
<li><p><strong>Limited Control:</strong> Fewer customization options compared to dedicated image services</p>
</li>
<li><p><strong>Format Restrictions:</strong> Automatic format conversion might not preserve quality</p>
</li>
<li><p><strong>Size Limitations:</strong> Processing very large images can timeout or fail</p>
</li>
</ul>
<p><strong>The Better Solution:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Custom optimization pipeline for high-quality zoom</span>
<span class="hljs-keyword">const</span> HighQualityImage = <span class="hljs-function">(<span class="hljs-params">{ src, alt }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    &lt;img 
      src={<span class="hljs-string">`https://your-cdn.com/transform?url=<span class="hljs-subst">${src}</span>&amp;q=95&amp;f=auto&amp;w=2000`</span>}
      alt={alt}
      style={{ maxWidth: <span class="hljs-string">'100%'</span>, height: <span class="hljs-string">'auto'</span> }}
    /&gt;
  );
};
</code></pre>
<p><strong>5. Build-Time and SSG Issues</strong></p>
<p><strong>The Problem:</strong> Static Site Generation (SSG) with Next.js Image can fail when image URLs are unavailable at build time or when dealing with large image sets.</p>
<p><strong>Real-World Example:</strong> Our product catalog generates static pages for 10,000+ products. During build time, some third-party image URLs become temporarily unavailable, causing the entire build to fail.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// This can break SSG builds</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params">{ params }</span>) </span>{
  <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> fetchProduct(params.id);

  <span class="hljs-keyword">return</span> {
    props: {
      product: {
        ...product,
        image: product.dynamicImageUrl <span class="hljs-comment">// Might be unavailable at build time</span>
      }
    }
  };
}
</code></pre>
<p><strong>What Goes Wrong:</strong></p>
<ul>
<li><p><strong>Build Failures:</strong> Invalid URLs cause build processes to crash</p>
</li>
<li><p><strong>Increased Build Times:</strong> Image optimization during build significantly slows deployment</p>
</li>
<li><p><strong>Memory Issues:</strong> Processing many large images can exhaust build server memory</p>
</li>
<li><p><strong>Inconsistent Results:</strong> Some images optimize successfully while others fail</p>
</li>
</ul>
<p><strong>The Better Solution:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Defer image loading to client-side</span>
<span class="hljs-keyword">const</span> ProductImage = <span class="hljs-function">(<span class="hljs-params">{ src, alt }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [imageSrc, setImageSrc] = useState(<span class="hljs-string">'/placeholder.jpg'</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Validate and set image source on client-side</span>
    <span class="hljs-keyword">const</span> img = <span class="hljs-keyword">new</span> Image();
    img.onload = <span class="hljs-function">() =&gt;</span> setImageSrc(src);
    img.onerror = <span class="hljs-function">() =&gt;</span> setImageSrc(<span class="hljs-string">'/fallback.jpg'</span>);
    img.src = src;
  }, [src]);

  <span class="hljs-keyword">return</span> &lt;img src={imageSrc} alt={alt} loading=<span class="hljs-string">"lazy"</span> /&gt;;
};
</code></pre>
<h3 id="heading-best-practices-for-nextjs-image-alternatives">Best Practices for Next.js Image Alternatives</h3>
<p>When you decide to skip Next.js Image, here are proven alternatives that maintain performance:</p>
<p><strong>1. Native Lazy Loading</strong></p>
<p>Modern browsers support native lazy loading:</p>
<pre><code class="lang-typescript">&lt;img src=<span class="hljs-string">"/image.jpg"</span> alt=<span class="hljs-string">"Description"</span> loading=<span class="hljs-string">"lazy"</span> /&gt;
</code></pre>
<p><strong>2. CDN-Based Optimization</strong></p>
<p>Use services like Cloudinary, Imgix, or ImageKit:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> optimizedUrl = <span class="hljs-string">`https://res.cloudinary.com/your-cloud/image/fetch/w_500,q_auto,f_auto/<span class="hljs-subst">${originalUrl}</span>`</span>;
</code></pre>
<p><strong>3. Custom Hook for Image Loading</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> useOptimizedImage = <span class="hljs-function">(<span class="hljs-params">src, options = {}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { width = <span class="hljs-number">500</span>, quality = <span class="hljs-number">80</span> } = options;
  <span class="hljs-keyword">return</span> <span class="hljs-string">`https://your-cdn.com/transform?url=<span class="hljs-subst">${<span class="hljs-built_in">encodeURIComponent</span>(src)}</span>&amp;w=<span class="hljs-subst">${width}</span>&amp;q=<span class="hljs-subst">${quality}</span>`</span>;
};
</code></pre>
<p><strong>4. Intersection Observer for Custom Lazy Loading</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> LazyImage = <span class="hljs-function">(<span class="hljs-params">{ src, alt, ...props }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [isLoaded, setIsLoaded] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isInView, setIsInView] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> imgRef = useRef();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(
      <span class="hljs-function">(<span class="hljs-params">[entry]</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (entry.isIntersecting) {
          setIsInView(<span class="hljs-literal">true</span>);
          observer.disconnect();
        }
      },
      { threshold: <span class="hljs-number">0.1</span> }
    );

    <span class="hljs-keyword">if</span> (imgRef.current) {
      observer.observe(imgRef.current);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> observer.disconnect();
  }, []);

  <span class="hljs-keyword">return</span> (
    &lt;div ref={imgRef} {...props}&gt;
      {isInView &amp;&amp; (
        &lt;img 
          src={src} 
          alt={alt}
          onLoad={<span class="hljs-function">() =&gt;</span> setIsLoaded(<span class="hljs-literal">true</span>)}
          style={{ 
            opacity: isLoaded ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>,
            transition: <span class="hljs-string">'opacity 0.3s ease'</span>
          }}
        /&gt;
      )}
    &lt;/div&gt;
  );
};
</code></pre>
<h3 id="heading-when-you-should-still-use-nextjs-image">When You SHOULD Still Use Next.js Image</h3>
<p>To be fair, Next.js Image is excellent for:</p>
<ul>
<li><p><strong>Static images</strong> in your <code>/public</code> directory</p>
</li>
<li><p><strong>Known, pre-configured domains</strong> with predictable image sources</p>
</li>
<li><p><strong>Low-traffic sites</strong> where optimization delays aren’t noticeable</p>
</li>
<li><p><strong>Simple blogs or portfolios</strong> with minimal image complexity</p>
</li>
<li><p><strong>When you need automatic blur placeholders</strong> and built-in lazy loading</p>
</li>
</ul>
<p>The Next.js Image component is a powerful tool, but it’s not a silver bullet. After months of real-world testing on a high-traffic e-commerce site, I’ve learned that <strong>premature optimization can be worse than no optimization</strong>.</p>
<p>Before reaching for Next.js Image, ask yourself:</p>
<ul>
<li><p>Are my image sources predictable and configurable?</p>
</li>
<li><p>Do I need real-time optimization, or can I pre-optimize?</p>
</li>
<li><p>Will the optimization delay impact user experience?</p>
</li>
<li><p>Am I dealing with high-volume image scenarios?</p>
</li>
<li><p>Do I have custom quality or format requirements?</p>
</li>
</ul>
<p>If you answered <strong>“NO”</strong> to the first question or <strong>“YES”</strong> to any of the others, consider alternatives. Sometimes a simple <code>&lt;img&gt;</code> tag with proper CDN optimization delivers better performance with less complexity.</p>
<h2 id="heading-mastering-nextjs-caching">Mastering Next.js Caching</h2>
<p>Have you ever noticed that some websites load really quickly while some others take a long time? Caching is a key part of how fast the website loads, and Next.js has powerful features to help you achieve it as well. You can make your app run faster and give users a better experience by optimizing the cache, even if you are not launching on <a target="_blank" href="https://vercel.com/">Vercel</a>, while potentially saving on hosting costs. Caching basically saves data that is used a lot so that it can be quickly retrieved. The server can serve a cached version of a page from your Next.js app when a user wants it instead of having it from scratch. This translates to:</p>
<ul>
<li><p>Lightning-fast load times: Pages that have been cached load almost instantly, giving your guests a smooth and responsive experience.</p>
</li>
<li><p>Less work for the server: When you serve stored pages, your server has more resources to do other things (<a target="_blank" href="https://vercel.com/blog/guide-to-fast-websites-with-next-js-tips-for-maximizing-server-speeds">which makes your application more scalable</a>)</p>
</li>
</ul>
<p>To put it simply, optimizing the cache keeps your Next.js app going at its fastest, which makes users happier and lowers server costs.</p>
<p>Next.js gives you a number of ways to improve your cache in a setting that doesn’t depend on Vercel. It automatically caches statically generated pages, improving performance for frequently accessed parts of your application. You can also control data fetching cache behavior by specifying the duration the browser stores the data, ensuring it stays fresh while optimizing speed. For advanced scenarios, you can build custom caching logic by using libraries or techniques like localStorage. By utilizing Next.js’s built-in caching mechanisms and data fetching strategies, you can greatly enhance your application performance without depending on external platforms like Vercel.</p>
<h3 id="heading-static-site-generation-ssg-1">Static Site Generation (SSG)</h3>
<p>The practice of assembling and displaying web pages at build time, as opposed to on demand, is known as static site generation. With HTML, JavaScript, and CSS among other static files, this produces a set that is prepared for user delivery. SSG is accomplished in Next.js via the use of functions like getStaticProps and getStaticPaths. Run during build time, these routines retrieve data and produce the HTML required for every page. You can retrieve data and send it as a prop to your page with getStaticProps, so the content is ready even before the user requests it.</p>
<p><strong>Benefits of Build Time Caching of Static HTML</strong></p>
<p>Pre-rendering of your information provides SSG a number of benefits:</p>
<ul>
<li><p><strong>Lightning-Quick Load Times</strong>: Your visitors will have a seamless experience as pages load nearly instantaneously because the HTML is already built.</p>
</li>
<li><p><strong>Greater Scalability</strong>: Because SSG doesn’t have to make content for each request, it lightens the strain on your server. This makes traffic handling by your application more efficient.</p>
</li>
<li><p><strong>Improved Search Engine Optimization</strong>: Pre-rendered content allows search engines to crawl and index your website faster. SSG may result in lower server costs because of a lower server load.</p>
</li>
</ul>
<p><strong>Implementation Tips and Best Practices for SSG in Next.js</strong></p>
<p>Now that you understand the core SSG process, here are some key implementation tips to optimize your workflow:</p>
<ul>
<li><p>Choose the Right Content: Periodically updated material, such as product pages or blog posts, is best served by SSG. It works less well with often-changing material.</p>
</li>
<li><p>Use getStaticProps: The Next.js function is your workhorse during the construction process. Use it to retrieve data and make it available to your pages.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params">context</span>) </span>{
   <span class="hljs-comment">// Fetch data here</span>
   <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/data'</span>);
   <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();
</code></pre>
<pre><code class="lang-typescript">   <span class="hljs-comment">// Return as props</span>
   <span class="hljs-keyword">return</span> {
     props: { data },
   };
  }
</code></pre>
</li>
<li><p>Dynamic Routes: For dynamic pages, use getStaticPaths and indicate which routes need to be pre-rendered.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticPaths</span>(<span class="hljs-params"></span>) </span>{
     <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/products'</span>);
     <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> response.json();

     <span class="hljs-comment">// Set fallback: false to indicate all pre-defined paths are generated at build time</span>
     <span class="hljs-keyword">return</span> {
       paths: paths, <span class="hljs-comment">// Assuming 'paths' is defined elsewhere with product IDs or slugs</span>
       fallback: <span class="hljs-literal">false</span>,
     };
   }
</code></pre>
</li>
</ul>
<h3 id="heading-incremental-static-regeneration-isg">Incremental Static Regeneration (ISG)</h3>
<p>ISG builds on the foundation of SSG. During the build process, Next.js renders your application’s HTML pages with the most recent data. These pre-built pages are subsequently served to users, providing extraordinary speed. While ISG uses pre-rendered pages in the same way that SSG does, it adds dynamism. When a request for a page is received, Next.js examines the cache. If a cached page is fresh (within a defined time frame), it is served immediately. If the cached material is obsolete, Next.js initiates a background re-generation process to retrieve new data and update the HTML content. The user continues to see the cached page while the update occurs in the background, ensuring a smooth experience.</p>
<p>It’s important to understand that ISR doesn’t achieve real-time updates on a static page at runtime. Why? This is because while the page is being generated in the background, the user continues to see the cached version. This regeneration can take a few seconds, depending on how you retrieve data. The validation window you set determines how fresh the item is. By default, there is no revalidation, but you can choose a time period (for example, 60 seconds) for Next.js to check your updates. This means the content may be slightly out of date compared to a real-time system.</p>
<p><strong>How to Implement ISR in Next.js Applications</strong></p>
<p>Next.js makes implementing ISR straightforward. Here’s a basic example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/data'</span>);
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
</code></pre>
<pre><code class="lang-typescript">  <span class="hljs-comment">// Revalidate the data every 60 seconds (can be adjusted)</span>
  <span class="hljs-keyword">return</span> {
    props: {
      data: data,
    },
    revalidate: <span class="hljs-number">60</span>, <span class="hljs-comment">// In seconds</span>
  };
}
</code></pre>
<p>In this example, getStaticProps retrieves and returns data as props. The revalidate parameters control how frequently Next.js checks for updates in the background. When the new data becomes available, the cached page is automatically refreshed. Incremental Static Regeneration allows you to build Next.js applications that are both fast and keep your content fresh. Understanding ISR’s strengths and limits allows you to use it to produce a seamless and up-to-date user experience.</p>
<h3 id="heading-cache-control-headers">Cache Control Headers</h3>
<p>Cache-control Headers are necessary for managing the caching behaviors of online resources. They teach browsers and intermediaries, such as CDNs, <a target="_blank" href="https://aws.amazon.com/caching/cdn/">how to handle caching</a>, which can have a substantial impact on a website’s performance and efficiency. They determine how, where, and how long the resources should be cached. They help to reduce utilization bandwidth and server burden, resulting in faster load times. They ensure that customers receive the most current materials without excessive requests.</p>
<p><strong>Setting up Cache Control Headers in Next.js</strong></p>
<p>While Next.js automatically configures some default Cache-Control Headers, you may want to change them for specific uses. Here is a summary on the options:</p>
<ul>
<li>During SSG, you can define Cache-Control headers within the getStaticProps function. This approach is ideal for static content with a set expiration time.</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// ... fetch data</span>
</code></pre>
<pre><code class="lang-typescript">  <span class="hljs-keyword">return</span> {
    props: {
      data: data,
    },
    revalidate: <span class="hljs-number">60</span>, <span class="hljs-comment">// Optional: revalidate every 60 seconds with ISR</span>
    cacheControl: <span class="hljs-string">'public, max-age=3600'</span>, <span class="hljs-comment">// Cache for 1 hour</span>
  };
}
</code></pre>
<ul>
<li>For API routes, you can set headers directly in the response object.</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
   <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/data'</span>);

   res.status(<span class="hljs-number">200</span>).json(data).setHeader(<span class="hljs-string">'Cache-Control'</span>, <span class="hljs-string">'public, max-age=86400'</span>); <span class="hljs-comment">// Cache for 1 day</span>
 }
</code></pre>
<p><strong>Best Practices for Cache Control Headers</strong></p>
<ul>
<li><p>Differentiate between static content (e.g., blog articles) and dynamic content (e.g., user profiles) and use appropriate headers. Static material can have longer cache periods, whereas dynamic content may need shorter caching or none at all.</p>
</li>
<li><p>Set appropriate max-age values based on your content’s update frequency as it specifies how long a resource can be cached before being considered stale</p>
</li>
<li><p>Use the immutable directive for really static items that never change (for example, photos or JavaScript files). This informs caches to never revalidate the resource, optimizing performance.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-comment">// ... fetch data (for non-immutable content)</span>

   <span class="hljs-keyword">return</span> {
     props: {
       data: data,
     },
     cacheControl: <span class="hljs-string">'public, immutable'</span>, <span class="hljs-comment">// Never revalidate</span>
   };
 }
</code></pre>
<ul>
<li>Use no-cache and no-store together with appropriate revalidation mechanisms (for example, SSR or ISR) to ensure that users always view the most recent version. However, use caution because they can have a considerable impact on performance if used excessively.</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-comment">// ... fetch data (for dynamic content)</span>

   <span class="hljs-keyword">return</span> {
     props: {
       data: data,
     },
     cacheControl: {
       <span class="hljs-comment">// Revalidate every 60 seconds with ISR (consider appropriate strategy)</span>
       maxAge: <span class="hljs-number">60</span>,
       noCache: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Invalidate cached data but doesn't prevent caching entirely</span>
       noStore: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Don't store data in any cache (use with caution)</span>
     },
   };
</code></pre>
<ul>
<li>Try out several <a target="_blank" href="https://stackoverflow.com/questions/62077589/setting-cache-control-header-for-static-file-serving-on-nextjs-default-server">Cache-Control Header Settings</a> and monitor real-world performance from browser developer tools in the network or timing tabs or tools like <a target="_blank" href="https://pagespeed.web.dev/">Google Speed Insights</a> or <a target="_blank" href="https://chromewebstore.google.com/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=en&amp;pli=1">Lighthouse</a>, and so on to determine the best mix of the benefits of caching and the freshness of the content.</li>
</ul>
<h3 id="heading-client-side-caching">Client Side Caching</h3>
<p>Client-side caching includes storing data obtained from the server on the user's browser. This cached data can be utilized for future requests, avoiding the need to retrieve from the server. Typical client-side caching methods include:</p>
<ul>
<li><p>Browser Cache (HTTP Cache): Using Cache-Control headers from the server, the browser stores resources in cache on its own. Some of these headers are already handled by Next.js by default.</p>
</li>
<li><p>Scripts known as “service workers” operate in the background of a webpage even when it isn’t being used actively. If there is cached data available, they can serve it and intercept network queries.</p>
</li>
<li><p>Web Storage: There are two primary choices for web storage offered by the browser:</p>
</li>
<li><p>localStorage: Information is kept around even when the browser window is closed.</p>
</li>
<li><p>sessionStorage: When a browser window or tab is closed, data is removed.</p>
</li>
</ul>
<h3 id="heading-cdn-integration">CDN Integration</h3>
<p>Picture a network of servers positioned throughout the globe. Such is a Content Delivery Network (CDN). By integrating CDN with your Next.js application, you essentially spread your static content — images, JavaScript, and CSS — over these servers. By bringing your material closer to users, loading times are greatly accelerated.</p>
<p><strong>Benefits of CDN Integration:</strong></p>
<ul>
<li><p><strong>Faster Load Times:</strong> By serving material from the closest CDN server, users’ experience is delivered with less latency.</p>
</li>
<li><p><strong>Greater Scalability:</strong> High traffic spikes can be managed by CDNs without affecting your primary server.</p>
</li>
<li><p><strong>Reduced Bandwidth Costs:</strong> Your server will be less taxed when static material is offloaded to the CDN, which may result in lower bandwidth bills.</p>
</li>
<li><p><strong>Increased Availability:</strong> Because CDNs are dispersed geographically, your material is still available even in the event that one server goes down.</p>
</li>
</ul>
<h3 id="heading-nextjs-cache-control-staletimes-revalidatepath-relavidatetags">Next.js Cache Control: staleTimes, revalidatePath, relavidateTags</h3>
<p>Enter two Next.js features that solve different pieces of this puzzle: <strong>staleTimes</strong> and <strong>revalidatePath</strong>. They both deal with caching, but they operate completely in different realms and serve distinct purposes.</p>
<p><strong>What is staleTimes?</strong></p>
<p>stateTimes is Next.js’s experimental solution for controlling client-side router cache duration. Think of it as a timer that determines how long your app keeps cached page data in the browser before fetching fresh content.</p>
<p>Here’s the basic setup:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// next.config.js</span>
<span class="hljs-keyword">const</span> nextConfig = {
  experimental: {
    staleTimes: {
      dynamic: <span class="hljs-number">30</span>,  <span class="hljs-comment">// 30 seconds for dynamic pages</span>
      <span class="hljs-keyword">static</span>: <span class="hljs-number">180</span>,  <span class="hljs-comment">// 3 minutes for static pages</span>
    },
  },
}
</code></pre>
<p>The configuration works with two key properties:</p>
<ul>
<li><p><strong>dynamic</strong>: Controls cache duration for pages that aren’t statically generated (default: 0 seconds in Next.js 15)</p>
</li>
<li><p><strong>static</strong>: Controls cache duration for statically generated pages and prefetched links (default: 5 minutes)</p>
</li>
</ul>
<p><strong>What is revalidatePath?</strong></p>
<p><code>revalidatePath</code> is your server-side cache invalidation tool. It’s like a precision strike that tells Next.js to throw away cached data for specific routes and fetch fresh content on the next visit.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { revalidatePath } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/cache'</span>

<span class="hljs-comment">// Revalidate a specific URL</span>
revalidatePath(<span class="hljs-string">'/blog/my-post'</span>)
<span class="hljs-comment">// Revalidate all URLs matching a pattern</span>
revalidatePath(<span class="hljs-string">'/blog/[slug]'</span>, <span class="hljs-string">'page'</span>)
<span class="hljs-comment">// Nuclear option: revalidate everything</span>
revalidatePath(<span class="hljs-string">'/'</span>, <span class="hljs-string">'layout'</span>)
</code></pre>
<p>Imagine you have a blog, and you add a new post:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/actions.ts</span>
<span class="hljs-string">'use server'</span>

<span class="hljs-keyword">import</span> { revalidatePath } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/cache'</span>
<span class="hljs-keyword">import</span> { db } <span class="hljs-keyword">from</span> <span class="hljs-string">'./db'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addPost</span>(<span class="hljs-params">formData</span>) </span>{
    <span class="hljs-comment">// Add new post to your database</span>
    <span class="hljs-keyword">await</span> db.post.create({
        data: {
            title: formData.get(<span class="hljs-string">'title'</span>),
            content: formData.get(<span class="hljs-string">'content'</span>),
        },
    })

    <span class="hljs-comment">// Immediately revalidate the blog listing page</span>
    revalidatePath(<span class="hljs-string">'/blog'</span>)
}
</code></pre>
<p>The function accepts two parameters:</p>
<ul>
<li><p><strong>path</strong>: The route to revalidate</p>
</li>
<li><p><strong>type</strong>: Either ‘page’ (specific page only) or ‘layout’ (page and all nested routes)</p>
</li>
</ul>
<p><strong>What is</strong> <code>revalidateTag</code>?</p>
<p>Next.js has a cache tagging system for fine-grained data caching and revalidation.</p>
<ol>
<li><p>When using <code>fetch</code> or <code>unstable_cache</code>, you have the option to tag cache entries with one or more tags.</p>
</li>
<li><p>Then, you can call <code>revalidateTag</code> to purge the cache entries associated with that tag.</p>
</li>
</ol>
<p>For example, you can set a tag when fetching data:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Cache data with a tagfetch(`https://...`, { next: { tags: ['a', 'b', 'c'] } })</span>
</code></pre>
<p>Then, call <code>revalidateTag</code> with a tag to purge the cache entry:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Revalidate entries with a specific tagrevalidateTag('a')</span>
</code></pre>
<p>There are two places you can use <code>revalidateTag</code>, depending on what you're trying to achieve:</p>
<ol>
<li><p>Route Handlers - to revalidate data in response to a third-party event (e.g., webhook). This will not invalidate the Router Cache immediately, as the Router Handler isn't tied to a specific route.</p>
</li>
<li><p>Server Actions - to revalidate data after a user action (e.g, form submission). This will invalidate the Router Cache for the associated route.</p>
</li>
</ol>
<h3 id="heading-cutting-redundant-data-fetches-with-reacts-cache-in-react-19">Cutting Redundant Data Fetches with React’s cache in React 19</h3>
<p>React 19 introduced new features that improve data fetching in server-side React apps. One of them is the cache function, a built-in mechanism for memorizing data of a function call on the server. For simpler terms, the cache function allows you to avoid repeating expensive computations or data fetches when the same input occurs again on a single render cycle. It does this through memoization, storing the results of function calls and reusing them in the future if the same inputs are passed.</p>
<p>The <code>cache</code> API is only available in React Server Components (RSC). In client-side React, you would use other techniques (like hooks <code>useMemo</code> and <code>useEffect</code>) for caching, but on the server, the <code>cache</code> function is the right tool.</p>
<p><strong>The problem of redundant data fetches</strong></p>
<p>In a framework such as Next.js 15, it’s common to break pages into components or even use parallel routes (multiple segments rendered concurrently). These components might need the same data. For example, two different parts of the page both require a user’s profile or a list of products.</p>
<p>Without caching, this often means making duplicate database (DB) or API calls. For instance, if two sibling components (or parallel route segments) each query the DB for the current user’s info, you’d normally end up hitting the DB twice for the same query. This slows your app, increases server load, and potentially leads to inconsistent data if one request finishes before the other.</p>
<p>In the past, avoiding this redundancy required workarounds like lifting data fetching up to a common parent and passing props down or implementing a manual caching layer. However, lifting the state up makes components less modular. Custom caching logic also gets messy. What we want is a way for each component to request the data it needs independently while automatically deduplicating identical requests during the render cycle. This is exactly the use case React’s <code>cache</code> function is designed to handle.</p>
<p><strong>How React’s</strong> <code>cache</code> <strong>works</strong></p>
<p>React’s <code>cache</code> function creates a memoized version of any asynchronous function. When you wrap a function with <code>cache</code>, React will store its result in memory the first time it's called. Subsequent calls to the cached function with the same arguments will return the cached result instantly, skipping the actual function execution. In other words, the first call is a cache miss (triggers the real fetch or computation), and later calls (with identical parameters) are cache hits that reuse the result.</p>
<p>This caching is scoped to a single server render lifecycle. During a server-side render, if multiple components invoke the same cached function with the same arguments, React runs the underlying operation (e.g., the DB query) only once. It prevents redundant, expensive operations by reusing the cached result. That avoids unnecessary network requests. This means fewer DB hits or API calls for that page render, leading to better performance and consistency. All components get the same result object, so they stay in sync.</p>
<p>Equally important, the cache is automatically cleared after the render is complete. React clears the cache after every server request. It invalidates all cached results at the end of each server request/render, so the next time you render that page (or another user requests it), React fetches fresh data.</p>
<p>There’s no need to worry about manual cache invalidation or stale data in subsequent requests. By design, each new request gets a new, empty cache. This makes the <code>cache</code> function a <strong>per-request memoization</strong>. Each call to <code>cache(fn)</code> returns a new memoized function with its own storage, and errors are cached the same way as successful results.</p>
<p>It differs from persistent caches (like data cached to disk or long-lived in-memory caches). Those would need explicit invalidation strategies, but this built-in cache is transient and lives only for the duration of the render. As the Next.js <a target="_blank" href="https://nextjs.org/docs/app/guides/caching">docs</a> note, the cache (for memoized fetches or functions) <em>"lasts the lifetime of a server request until the React component tree has finished rendering"</em> and is not shared across requests.</p>
<p>In practice, this means each page load or navigation gets fresh data, which is ideal for most cases where you want real-time updated info on a new request.</p>
<p><strong>Using React’s</strong> <code>cache</code> <strong>in a Next.js App (Supabase Example)</strong></p>
<p>Let’s walk through a concrete example to see the <code>cache</code> function in action. With a Next.js app using the App Router, you have two parallel route segments on a dashboard page, say, a user profile section and a sidebar with user stats. Both segments need to retrieve the user's profile data from the DB. We'll use Supabase as the DB client for this example (Supabase provides a JS client to query your DB directly from server code).</p>
<p>First, we can set up a Supabase client (for example, using the project URL and anon key in an environment config). Then we write a data-fetching function to get the user profile. We’ll wrap this function with the <code>cache</code> function:</p>
<blockquote>
<p><em>Next.js 15 defaults</em> <code>fetch</code> to <code>cache: 'no-store'</code>. Identical calls are still deduplicated in one render, but each new request fetches fresh data unless you opt in with <code>cache: 'force-cache'</code> or revalidation.</p>
</blockquote>
<pre><code class="lang-typescript"><span class="hljs-comment">// utils/dataFetcher.ts</span>
<span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/supabase-js'</span>;
<span class="hljs-keyword">import</span> { cache } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);

<span class="hljs-comment">// Define a cached function to fetch a user profile by ID</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getUserProfile = cache(<span class="hljs-keyword">async</span> (userId: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
    .from(<span class="hljs-string">'profiles'</span>)
    .select(<span class="hljs-string">'*'</span>)
    .eq(<span class="hljs-string">'id'</span>, userId)
    .single();

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;

  <span class="hljs-keyword">return</span> data;
});
</code></pre>
<p>In the code above, <code>getUserProfile</code> is a memoized function. The first time you call <code>getUserProfile('abc123')</code> for a given request, it will actually run the query against Supabase. If you call <code>getUserProfile('abc123')</code> again (anywhere else in the React tree during the same render), it will instantly return the cached result instead of querying the DB a second time. This pattern can be seen in real projects. For example, a Supabase utility might export cached queries like this to prevent duplicate calls.</p>
<p>Now, suppose our Next.js page uses parallel routes or multiple components that need this data:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/dashboard/@main/page.tsx</span>
<span class="hljs-keyword">import</span> { getUserProfile } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/utils/dataFetcher'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MainSection</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> getUserProfile(userId);
  <span class="hljs-keyword">return</span> &lt;ProfileDetails user={user} /&gt;;
}

<span class="hljs-comment">// app/dashboard/@sidebar/page.tsx</span>
<span class="hljs-keyword">import</span> { getUserProfile } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/utils/dataFetcher'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Sidebar</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> getUserProfile(userId);
  <span class="hljs-keyword">return</span> &lt;UserStats user={user} /&gt;;
}
</code></pre>
<p>In this simplified example, <code>MainSection</code> and <code>Sidebar</code> are two parallel segments (or could simply be two sibling server components) that both fetch the user’s profile. Thanks to React’s <code>cache</code>, the database is hit only once for <code>getUserProfile(userId)</code> during the server render. The first call (say, in <code>MainSection</code>) will query the DB (cache miss), and the second call (in <code>Sidebar</code>) will find the result already in cache (cache hit), avoiding another DB round-trip. Without the cache, we would have executed two identical queries to Supabase. With <code>cache</code>, React makes sure those components share the work and render the same snapshot of data.</p>
<p>It’s worth noting that this caching works for any kind of function, not just DB calls. You could use it to memoize expensive calculations or calls to other APIs or CMS systems. The key is that the function should be called within the React server render cycle (e.g., inside an <code>async</code> server component or during data fetching in a Next.js route).</p>
<p>If you try to call the cached function outside of rendering (for example, at the top level of your module when defining it or in a non-React context), it will still execute but won’t use React’s <code>cache</code>. React only provides cache access during the rendering of components. In practice, you usually call the cached function inside your server components as shown above, which is the correct usage.</p>
<p><strong>Benefits of Using React’s</strong> <code>cache</code></p>
<ul>
<li><p><strong>Fewer DB/API calls:</strong> By deduplicating identical requests, you drastically cut down on redundant calls. The same function called multiple times with the same arguments will hit the server or DB only once. This reduces server workload and network traffic.</p>
</li>
<li><p><strong>Improved Performance:</strong> Reusing cached data results in faster response times and a smoother user experience. The page can render faster since subsequent components don’t have to wait for repeat fetches. In our example, the second component gets the data almost instantly from memory.</p>
</li>
<li><p><strong>Consistent Data:</strong> When multiple parts of the UI request the same info, using a single cached result means they all render with the same data. There’s no risk of one component showing stale data while another fetches fresh data moments later. During that render, they share the exact result.</p>
</li>
<li><p><strong>Simplified Code:</strong> React’s <code>cache</code> lets each component fetch what it needs without complex prop drilling or higher-level coordination. This keeps components more independent and readable, while the caching happens transparently under the hood. You don’t need ad hoc context providers or singletons to share data. Just call the cached function wherever needed.</p>
</li>
<li><p><strong>No Manual Invalidation Needed:</strong> Because the cache resets on every new request, you get fresh data on the next render by default. This ephemeral caching means you don’t have to write extra logic to invalidate or update the cache for new requests. (If you do want to cache across requests, you’d use other Next.js opt-in caching features, but that’s a different mechanism beyond our scope here.)</p>
</li>
</ul>
<h2 id="heading-how-to-fix-the-most-annoying-hydration-errors-in-nextjs">How To Fix the Most Annoying Hydration Errors In Next.js</h2>
<p>We have all been there.</p>
<p>We excitedly spin up a Next.js project, everything looks good in development, and then — boom — a wild “Hydration failed“ error appears in the console when you hit to production.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755691457815/80267e90-3b19-48c9-879c-57af410eb588.webp" alt class="image--center mx-auto" /></p>
<p>You <em>refresh</em>.<br />You <em>curse</em>.<br />You <em>Google</em>.<br />You <em>copy-paste</em> a random <code>useEffect</code> fix from Stack Overflow.<br />And yet, the error <strong>still</strong> haunts you.</p>
<p>Don’t worry, I have been down this road too, and I’m here to help you actually understand why hydration errors happen in Next.js and how to fix them properly.</p>
<h3 id="heading-first-what-even-is-a-hydration-error">First, what even is a hydration error?</h3>
<p>Next.js uses server-side rendering to send the full-rendered HTML page to the browser. Then React takes over on the client side, reconciling what was sent on the server with what it needs to render on the client.</p>
<p>A hydration error happens when React notices a mismatch between what was pre-rendered on the server and what’s rendered on the client.</p>
<pre><code class="lang-typescript">Warning: Text content did not match. Server: <span class="hljs-string">"Hello, John"</span> Client: <span class="hljs-string">"Hello, Jane"</span>
</code></pre>
<blockquote>
<p><em>Translation:<br />The server expected</em> <strong><em>“Hello, John”*</em></strong>, but by the time the client rendered, it became<em> **</em>“Hello, Jane”<em>**</em>.*</p>
</blockquote>
<p>React freaks out because it doesn’t know which version is correct.</p>
<h3 id="heading-common-causes-of-hydration-errors-and-how-to-fix-them">Common Causes Of Hydration Errors (and How To Fix Them)</h3>
<p><strong>1. State That Changes on Mount (a.k.a. The Classic useEffect Trap)</strong></p>
<p>You might be fetching data <strong>only on the client side</strong>, which means the content is different on the initial render vs. after hydration.</p>
<p>❌ The Problem</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755692114501/27159147-ad90-4162-98a2-5ef8ad7274e9.webp" alt class="image--center mx-auto" /></p>
<p><strong>Why does this fail?</strong></p>
<ul>
<li><p>On the server, it renders <strong>“Welcome, Guest”</strong>.</p>
</li>
<li><p>On the client, <code>useEffect</code> runs and updates it to <strong>"Welcome, John Doe"</strong>.</p>
</li>
<li><p>React panics because the DOM content doesn’t match.</p>
</li>
</ul>
<p><strong>✅ The Fix: Use</strong> <code>useState</code> <strong>Only If You Need It</strong></p>
<p>Instead of <strong>hydrating with different content</strong>, make sure the state is consistent on both the server and client:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755692132071/0fef9de6-8ed9-4242-aa78-f7df21ede8f4.webp" alt class="image--center mx-auto" /></p>
<blockquote>
<p>***Key Takeaway:***<em>Fetch data</em> <strong><em>on the server</em></strong> <em>if possible, so the client and server match.</em></p>
</blockquote>
<p><strong>2. Using</strong> <code>window</code><strong>,</strong> <code>document</code><strong>, or</strong> <code>localStorage</code> <strong>During Render</strong></p>
<p>Hydration errors often happen when you try to access browser-specific APIs <strong>before the component mounts.</strong></p>
<p><strong>❌ The Problem</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755692155858/b606672b-bb29-49ed-82ec-b24a08de47c1.webp" alt class="image--center mx-auto" /></p>
<p><strong>Why does this fail?</strong></p>
<ul>
<li><p><code>localStorage</code> <strong>doesn’t exist on the server</strong>.</p>
</li>
<li><p>Your component <strong>crashes</strong> because it tries to access <code>localStorage</code> before hydration.</p>
</li>
</ul>
<p><strong>✅ The Fix: Use</strong> <code>useEffect</code> to Access the Browser API</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755692172420/77485c05-a5a6-48ac-94f8-f86f92ff31e9.webp" alt class="image--center mx-auto" /></p>
<blockquote>
<p>***Key Takeaway:***<strong><em>Only use browser APIs inside</em></strong> <code>useEffect</code>, since it runs <strong>after</strong> hydration.</p>
</blockquote>
<p><strong>3. Components That Render Differently on the Server and Client</strong></p>
<p>Sometimes, your component’s <strong>initial render is different</strong> between SSR and CSR.</p>
<p><strong>❌ The Problem</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755692191647/05aa1dd6-cd0f-417b-a1d1-59e9283f294e.webp" alt class="image--center mx-auto" /></p>
<p><strong>Why does this fail?</strong></p>
<ul>
<li><p>The <strong>server</strong> renders one timestamp.</p>
</li>
<li><p>The <strong>client</strong> renders a different timestamp.</p>
</li>
<li><p>Boom! Hydration error.</p>
</li>
</ul>
<p><strong>✅ The Fix: Only Render on the Client</strong></p>
<p>Use <strong>dynamic imports with</strong> <code>ssr: false</code> to disable SSR:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755692221789/28a4afcb-2bb0-4015-9550-12a8b42b9792.webp" alt class="image--center mx-auto" /></p>
<p>Or, use <code>useEffect</code> to update the time <strong>after</strong> hydration:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755692245792/13f4d521-1a81-455c-b674-23e89da5ce23.webp" alt class="image--center mx-auto" /></p>
<blockquote>
<p>**<em>Key Takeaway:<br />If your component depends on the</em> <strong><em>current time, user data, or client-only state</em></strong>*, either* <strong><em>disable SSR</em></strong> <em>or render it</em> <strong><em>only after hydration</em></strong>*.*</p>
</blockquote>
<p><strong>The Nuclear Option:</strong> <code>suppressHydrationWarning</code></p>
<p>If all else fails, <strong>Next.js lets you tell React to ignore the mismatch</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755692262793/139c6cfc-661f-4af4-8452-c7a2a1eb45dd.webp" alt class="image--center mx-auto" /></p>
<blockquote>
<p>***Use this only if you know what you’re doing.***<em>It</em> <strong><em>hides</em></strong> <em>the warning but doesn’t actually fix the issue.</em></p>
</blockquote>
<h2 id="heading-how-i-made-a-nextjs-app-load-10x-faster">How I Made a Next.js App Load 10x Faster</h2>
<h3 id="heading-set-proper-http-headers-for-caching">Set proper HTTP Headers for Caching</h3>
<p>Caching is essential for improving performance and reducing server load. When a browser caches static assets (like JavaScript, CSS, and images), it can reuse those files instead of downloading them again on every visit. This significantly speeds up page loads for returning users.</p>
<p>For example, by setting a <code>Cache-Control</code> <a target="_blank" href="https://nextjs.org/docs/app/api-reference/functions/headers">header</a> ike <code>public, max-age=31536000, immutable</code>, you tell the browser to cache the file for one year and not check for updates. This works well for assets that don’t change frequently, such as fonts, logos, or versioned build files.</p>
<p>You can configure caching headers in <code>next.config.js</code> using the <code>headers()</code> async function. This ensures consistent behavior across all your static files and can boost your app’s performance, especially on repeat visits.</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = {
  <span class="hljs-keyword">async</span> headers() {
    <span class="hljs-keyword">return</span> [
      {
        source: <span class="hljs-string">'/:all*'</span>,
        headers: [
          { key: <span class="hljs-string">'Cache-Control'</span>, value: <span class="hljs-string">'public, max-age=31536000, immutable'</span> },
        ],
      },
    ];
  },
};
</code></pre>
<h3 id="heading-embrace-server-components-to-minimize-client-side-javascript">Embrace Server Components to minimize client-side JavaScript</h3>
<p>One of the biggest features in Next.js 13 (fully embraced in Next.js 15) is React Server Components (SRCs). RSCs allow you to render the component on the server and send the pure HTML to the client, without shipping any JavaScript bundles to the browser. Results? Drastically reduce JS payloads and faster load times. In other words, components that don’t need the interactivity can be delivered that are already “cooked“ from the server — the browser just needs to display the HTML without any hydrations and JavaScript bundles.</p>
<p><strong>Why it helps:</strong> Every bit of JavaScript that the browser doesn’t have to download and execute makes the page load faster and respond quicker. By keeping as much as possible on the server, you reduce the bundle size and improve startup time. As React expert Josh Comeau notes, <em>“Server Components don’t get included in the bundle size, which reduces the amount of JavaScript that needs to run, leading to better performance.”</em> In practice, we have seen a project where moving a heavy data processing from the client-side to the server cut the client-side bundle to 30%, significantly improving load time*.*</p>
<p><strong>How to use it:</strong> In Next.js App Router, components are <em>served by default</em> (unless you add the <code>"use client"</code> directive). Design your pages so that any component that doesn’t require browser interactivity (displaying data, static content, etc.) remains a Server Component. Fetch data directly in these components (e.g. using <code>fetch()</code> in an async component) and render the content on the server. For parts that <em>do</em> need interactivity (e.g., a button click handler or dynamic state), isolate them into small <strong>Client Components</strong> <code>"use client"</code> at the top. This way, you send minimal JS to the client–only the code needed for interactive elements – while the bulk of the UI arrives as static HTML.</p>
<p><strong>Before/After example:</strong> Imagine a dashboard page that originally loads all data through a client-side JavaScript and renders a big React bundle on the browser. Users see a loading spinner for a couple of seconds while waiting for the browser to fetch data. By refactoring to use Server Components, the HTML page now comes pre-filled with data (no big client fetch needed), and the JS bundle size drops by 50%. The <strong>Time to First Byte (TTFB)</strong> improved because the server does data fetching in parallel, and <strong>First Input Delay (FID)</strong> improved since the browser has less JavaScript to execute before handling interactions. Users can now see the content instantly and are able to interact with the content within milliseconds of page load.</p>
<h3 id="heading-stream-and-selectively-hydrate-for-instant-interaction">Stream and Selectively Hydrate for Instant Interaction</h3>
<p>Delivering HTML fast is only half of the story — we also want users to interact with the page as soon as possible, without waiting for all JavaScript to finish loading. This is where <strong>React 18’s streaming SSR and selective hydration</strong> come into play. Next.js 15 (powered by React 18+) can stream HTML in chunks and hydrate portions of the UI incrementally, rather than blocking on the entire page. In practice, that means your app can show useful content sooner and become interactive faster, improving metrics like TTFB and FID.</p>
<p>With <strong>Streaming Server-Side Rendering</strong>, the server doesn’t wait for the entire page before sending HTML. Instead, it can send a piece of the page as soon as possible when the data is ready (often gated by React <code>&lt;Suspense&gt;</code> boundaries). Meanwhile, <strong>Selective Hydration</strong> ensures that once those HTML chunks arrive. If the user interacts with the part of the page that hasn’t hydrated yet, React will prioritize hydrating that part first — no more waiting for the entire app to hydrate before any interactions work.</p>
<p><strong>Why it helps:</strong> Traditional SSR would send the full HTML, but the page stayed non-interactive until all the JavaScript was downloaded and all components were hydrated in one go (an “all-or-nothing” hydration). That could lead to a long delay in large apps, poor FDI, and a frustrating user experience. With streaming and selective hydration, <strong>smaller components can hydrate and become interactive immediately without waiting for larger, slower parts</strong>. This greatly improves <strong>First Contentful Paint (FCP)</strong> and FID. React 18’s architecture is a game-changer: <em>“HTML streaming sends partial HTML as it’s ready, and selective hydration means you can start interacting with the app before all components have hydrated.”</em>.</p>
<p><strong>How to use it:</strong> Next.js handles a lot of this automatically under the hood, but you should structure your app to take advantage of it. Use React’s <code>&lt;Suspense&gt;</code> boundaries to wrap parts of the UI that can load asynchronously. For example, you might suspense-wrap a product reviews section or user-specific info. Provide a lightweight <code>fallback</code> (like a spinner or placeholder) that can be rendered immediately. Next.js will stream the page HTML with the fallback in place of the slow section, and hydrate the rest. Once the data for that section is ready, the server streams the HTML for it, and React swaps in the real content and hydrates it. The key is: <strong>split your UI into bite-sized chunks</strong> and use Suspense for anything that might delay rendering. This enables progressive hydration.</p>
<p><strong>Real-world example:</strong> The Next.js team introduced <strong>Partial Prerendering</strong> in v15, which combines streaming and caching strategies. For instance, a dashboard page can prerender static metrics at build time (so they show up instantly) and stream in user-specific live data (like recent activity) when ready. The static parts are interactive immediately, and the dynamic part hydrates once loaded. This approach “significantly improves TTFB and LCP” by getting useful content on screen fast. In one experiment, enabling streaming SSR with Suspense cut the <strong>Largest Contentful Paint</strong> from ~3s to ~1.5s, because the largest element (a hero image and headline) was sent immediately and not held up by slower widgets. Users could also click navigation links almost right away, whereas before they had to wait for the entire app bundle to load. The page felt <strong>instant</strong>.</p>
<h3 id="heading-optimize-images-for-faster-loads-use-nextimage">Optimize Images For Faster Loads (Use Next/Image)</h3>
<p>High-quality images are often the largest part of the page, so optimizing images is one of the impactful things we can do to improve load times and LCP. Next.js provides a built-in solution: the <code>&lt;Image&gt;</code> component (<code>next/image</code>), which handles a ton of images for you automatically. By using Next.js’s Image Components for all your images, you will get out-of-the-box performance benefits:</p>
<ul>
<li><p><strong>Responsive sizing:</strong> It will <em>automatically serve the right size image</em> for each device, generating multiple versions and using modern formats like WebP. This avoids sending a huge 2000px-wide image to a mobile device that only needs 400px, saving bandwidth and time.</p>
</li>
<li><p><strong>Lazy loading:</strong> Images are by default lazy-loaded (only fetched when about to scroll into view), which <strong>dramatically reduces initial load time</strong>. Studies show that loading images on scroll instead of all upfront can decrease initial page load time by up to <em>60%</em>.</p>
</li>
<li><p><strong>Preventing layout shift:</strong> Next/Image fixes a common culprit of bad CLS by requiring width/height (or using intrinsic sizes) so the browser knows the image’s space in advance. No more content jumping around when images load — it’s handled.</p>
</li>
<li><p><strong>Modern formats &amp; compression:</strong> Next.js will automatically convert and serve images in newer formats like <strong>WebP/AVIF</strong> when supported, often 30% smaller than JPEG/PNG for the same quality. It also allows setting quality to balance size vs clarity. All of this means faster loads for users.</p>
</li>
<li><p><strong>Blur-up placeholders:</strong> You can enable a low-res blurred placeholder that shows while the image loads, giving an immediate preview and improving perceived performance. This is a nice touch to avoid blank spaces.</p>
</li>
</ul>
<p>In short, Next.js’s image optimization <strong>delivers smaller, smarter images and defers non-critical ones</strong>, boosting your LCP and overall performance. As the docs put it, the Next/Image component provides <em>“visual stability (no layout shift) and faster page loads by only loading images when they enter the viewport, with optional blur placeholders”</em>. And you hardly have to do a thing — just use <code>&lt;Image src={...} width={...} height={...} /&gt;</code> instead of a raw <code>&lt;img&gt;</code> tag.</p>
<p><strong>Pro Tips:</strong></p>
<ul>
<li><p><strong>Always specify dimensions</strong> (width and height) for your images (or use <code>fill</code> for responsive layout). This ensures Next can reserve space to avoid CLS. If you import a static image, Next will auto-populate its intrinsic width/height for you.</p>
</li>
<li><p><strong>Use</strong> <code>priority</code> for above-the-fold images (like hero banners or logo) to load them ASAP, and let less important images stay lazy. This improves the Largest Contentful Paint if that image is the LCP element.</p>
</li>
<li><p><strong>Leverage the</strong> <code>sizes</code> <strong>attribute</strong> on <code>&lt;Image&gt;</code> for responsive layouts. This helps the browser choose the optimal image variant (e.g. serve a smaller image on mobile).</p>
</li>
<li><p>If you have many icons or small graphics, consider <strong>SVG</strong> or icon fonts, or use CSS sprites, to reduce HTTP requests. But for photos and complex imagery, Next/Image is your best friend.</p>
</li>
</ul>
<p><strong>Before/After example:</strong> A travel blog homepage was struggling with an LCP of 4.0 seconds due to multiple large image thumbnails loading at once. By switching those <code>&lt;img&gt;</code> tags to Next <code>&lt;Image&gt;</code> with proper <code>sizes</code> and enabling lazy loading, the initial payload dropped by several MB. The LCP (which was the hero image) improved to 1.8s (well under the 2.5s good threshold), and overall page weight went down ~70%. The CLS issues caused by images suddenly popping in were eliminated (CLS went from 0.25 to near 0). The site felt snappy, and images still looked great – they were just delivered in a smarter way.</p>
<h3 id="heading-optimize-fonts-and-prevent-layout-shifts-use-nextfont">Optimize Fonts and Prevent Layout Shifts (Use Next/Font)</h3>
<p>Custom web fonts can subtly slow down your site and even cause layout jank (text shifting or appearing late). In Next.js 15, you have a powerful tool to optimize fonts: the <code>next/font</code> module. This utility will automatically handle font loading best practices — including self-hoisting fonts, preloading them, and controlling how they swap — all to boost performance.</p>
<p>When you use <code>next/font</code> (either with Google Fonts or your custom fonts), Next.js will:</p>
<ul>
<li><p>Inline critical font CSS and <strong>remove external network requests</strong> to font providers. This means no more waiting on Google Fonts servers; the font files are served from your own site, often faster and more reliably.</p>
</li>
<li><p>It <strong>preloads the fonts</strong> and uses efficient loading strategies. By default, Next fonts use <code>font-display: swap</code> (or similar) to avoid blocking text from rendering. Text will show in a fallback font immediately and then swap to the custom font when ready, which <em>prevents long invisible text paint delays</em> (important for good FID).</p>
</li>
<li><p>Next.js can even <strong>subset fonts</strong> (only include the characters you need) or use variable fonts to reduce the number of font files. All of this reduces the download size for typography.</p>
</li>
</ul>
<p>According to Vercel’s guidance, <em>“next/font will automatically optimize your fonts (including custom fonts) and remove external network requests for improved privacy and performance.”</em> This improves performance by cutting out an entire round-trip to fetch fonts and by ensuring text is visible ASAP, avoiding a flash of invisible text (FOIT) or sudden layout shifts when fonts load (FOIT/flash of unstyled text can cause CLS when the font metrics differ).</p>
<p><strong>Tips for fonts:</strong></p>
<ul>
<li><strong>Use</strong> <code>next/font/google</code> <strong>for Google Fonts</strong>: Instead of <code>&lt;link&gt;</code> tags in your <code>&lt;head&gt;</code>, use the Next font loader. For example:</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Roboto } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/font/google'</span>;
<span class="hljs-keyword">const</span> roboto = Roboto({ subsets: [<span class="hljs-string">'latin'</span>], weight: <span class="hljs-string">'400'</span> });
<span class="hljs-comment">// then in your layout/component:</span>
&lt;div className={roboto.className}&gt;Hello&lt;/div&gt;
</code></pre>
<p>This ensures the font CSS is included in the build and the font is preloaded.</p>
<ul>
<li><p><strong>Use variable fonts or limit weights:</strong> If possible, use a variable font that covers multiple weights/styles in one file. This reduces the number of font files to load. For example, the Inter font variable version can cover many styles in one file.</p>
</li>
<li><p><strong>Include fallbacks:</strong> Choose a fallback system font that has similar metrics to your web font and include it in your CSS stack (e.g. <code>font-family: Roboto, sans-serif;</code>). This way if the custom font is delayed, the fallback is used without much visual difference. Next/font helps here by simplifying the setup.</p>
</li>
<li><p><strong>Beware of huge font files:</strong> If your font file is very large (many glyphs or languages), consider using subsets (only the characters needed) or separate font files for different locales. Unused font glyphs are just dead weight.</p>
</li>
</ul>
<p>By optimizing fonts, you’ll see <strong>improvements in CLS and FCP</strong>. No more pages where content jumps around once the font loads or, worse, text that isn’t visible for a second. It’s a small tweak that makes your site feel polished and fast. In our experience, moving from a standard Google Fonts embed to Next’s automatic font optimization shaved about 200ms off the <em>First Contentful Paint</em> on a news site (since the text could render immediately with fallback and then swap smoothly). Core Web Vitals improved: CLS went practically to zero once we eliminated the layout shift that occurred when the custom font kicked in. Next.js 15’s font handling is robust — by using it, you basically check off another big item in the performance list with minimal effort.</p>
<h3 id="heading-analyze-and-trim-your-bundles-bundle-analysis-and-tree-shaking">Analyze and Trim Your Bundles (Bundle Analysis and Tree Shaking)</h3>
<p>Sometimes the biggest performance gains come from simply shipping less code. Large JavaScript bundles delay both download and execution, hurting metrics like TTI (Time To Interactive) and FID. That’s why a key step in optimization is to analyze your bundles and eliminate anything that isn’t absolutely needed on the client. The gold: Keep your client-side JavaScript bundles as lean as possible.</p>
<p>Start with bundle analysis: Next.js provides an official plugin for bundle analysis (<code>@next/bundle-analyzer</code>). Enable this to get the visual tree map of your JS bundles. This will show you the size of each npm package and module in your app. Often, you will discover some surprising things: maybe a profile or a big library being included by accident, or duplicate copies of a dependency. As a best practice: “Regularly use tools like Bundle Analyzer to visualize your bundle composition and identify opportunities for optimization“.</p>
<p><strong>What to look for:</strong></p>
<ul>
<li><p>Large libraries: Do you really need that heavy date library, or can you use a lighter alternative? For example, moment.js (huge) could be replaced with a smaller library or native Intl APIs. If a library is necessary, consider importing only specific parts (many libraries support modular imports)</p>
</li>
<li><p>Duplication: Ensure you are not importing two versions of a library. Bundle Analyzer will highlight if, say, lodahsh is included twice. This can happen if you have multiple versions in sub-dependencies. Resolve them or use a consistent version to avoid bloat.</p>
</li>
<li><p>Dead code: Tree Shaking usually removes code you don’t use, but if only that code is written in a tree-shaking way (in ES module). Ensure libraries are up to date and use ESM, and avoid sneaky patterns that prevent tree-shaking(like importing an entire library when you only need one).</p>
</li>
</ul>
<p>Modern build tools can eliminate a lot of dead code. In fact, projects leveraging aggressive tree-shaking often see 30%-50% reductions in bundle size. Next.js (with Turbopack and Webpack 5) will tree-shake as much as dependencies allow it. You can help by not importing things you don’t need. For example, if you only need an icon from an icon set, don’t import the whole set.</p>
<p><strong>Actionable steps to trim bundles:</strong></p>
<ul>
<li><p><strong>Run</strong> <code>next build</code> <strong>with analysis</strong> (using <code>ANALYZE=true</code> environment or the plugin) and open the bundle report. Identify top offenders.</p>
</li>
<li><p><strong>Remove or split out heavy modules:</strong> If you find a module that’s huge and only used on one page, consider dynamically importing it (see next tip) so it’s not in the main bundle. Or find a lighter alternative.</p>
</li>
<li><p><strong>Optimize dependencies:</strong> Import only what you use. For instance, <code>import lodash</code> brings in everything (if not tree-shaken); instead, do <code>import debounce from 'lodash/debounce'</code> to get that one function (or use lodash-es, which is tree-shakable). Similarly, for date-fns, import individual functions instead of the whole library.</p>
</li>
<li><p><strong>Polyfills:</strong> Next.js by default polyfills only as needed. But double-check you’re not unintentionally pulling heavy polyfill packages. Use core-js with targets if needed to avoid full polyfills.</p>
</li>
<li><p><strong>Strip dev code:</strong> Ensure <code>process.env.NODE_ENV</code> is set to production in the build (Next does this by default), so that any dev-only code or logging is dropped.</p>
</li>
</ul>
<p>By iteratively trimming the fat, you can often get your main bundle to well under 100 KB gzipped (depending on the app). For example, one of our projects had a ~300 KB bundle; after analysis, we removed an unused markdown parser and switched a charts library for a lighter one, dropping to ~90 KB. The payoff was visible: <strong>faster load and interactivity</strong>. As one guide noted, even going from ~150KB to under 100KB can make a difference in load time. And of course, smaller bundles mean less JavaScript blocking the main thread, improving FID.</p>
<p>Remember, “reduce code on the client to a minimum“ is the core principle for performance. Every byte and every millisecond counts. By shipping only what is necessary, you not only speed up your app but also reduce the memory usage and battery drain on devices. Bundle Analysis and Tree-Shaking are your allies in this quest for a slimmer, faster Next.js app.</p>
<h3 id="heading-code-split-by-dynamic-imports-load-only-what-you-need">Code-Split By Dynamic Imports (Load Only What You Need)</h3>
<p>Even after trimming your bundle, don’t load all that code upfront if users don’t immediately need it. Code-splitting is a technique to split your JS bundle into smaller chunks that can be loaded on demand. In Next.js, you automatically get code-splitting by page; each page’s JS is split out, and you can and should go further with dynamic imports for parts of your pages that can be deferred. The ideal is to ship the minimal code for the initial load, and load the rest asynchronously when needed.</p>
<p>Using Next.js dynamic imports (or React.lazy), you can turn virtually any component into a separately loaded chunk. For example, suppose you have a very large chart component of the dashboard that isn’t visible until the user scrolls down or interacts — you can import it dynamically so it’s not in the initial JS. This improves initial load times dramatically.</p>
<p><strong>Benefits:</strong> Studies indicate that a well-structured code-splitting strategy can improve initial loading performance by ~40%. We’ve seen cases where dynamic imports reduced the initial bundle by 50%, making the app load <strong>twice as fast</strong> on first visit. It also has a business impact: faster initial loads can lead to higher conversion; one report noted 20–25% increased conversions with faster pages (users stick around when the first page loads quickly!).</p>
<p><strong>How to do it in Next.js:</strong></p>
<ol>
<li><strong>Dynamic Imports In Next.js</strong></li>
</ol>
<p>Dynamic Imports are a cornerstone of lazy loading in Next.js, enabling code-splitting at the component level. This powerful feature allows you to load specific components or entire libraries when they are required by the user, rather than including them in the initial JavaScript bundle. Next.js provides the <code>next/dynamic</code> utility, which is a composite of React's <code>React.lazy()</code> and <code>Suspense</code>, offering a seamless way to implement this optimization.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Chart = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/Chart'</span>), {
  loading: <span class="hljs-function">() =&gt;</span> &lt;p&gt;Loading chart...&lt;<span class="hljs-regexp">/p&gt;, /</span><span class="hljs-regexp">/ Displays this while the Chart component loads
});

export default function Dashboard() {
  return (
    &lt;div&gt;
      &lt;h2&gt;Sales Dashboard&lt;/</span>h2&gt;
      &lt;Chart /&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p><strong>Key Points:</strong></p>
<ul>
<li><p><strong>The HeavyComponent is excluded from the initial bundle</strong>: This means the JavaScript for <code>HeavyComponent</code> is not downloaded when the <code>Home</code> page initially loads.</p>
</li>
<li><p><strong>Loaded only when rendered:</strong> The component’s code is fetched and executed only when React attempts to render <code>HeavyComponent</code> in the DOM.</p>
</li>
<li><p><strong>Automatic Code Splitting:</strong> Next.js automatically handles the creation of separated JavaScript chunks for dynamically imported components. Server Components are code-split by default, and lazy loading specifically applies to Client Components.</p>
</li>
</ul>
<ol start="2">
<li><strong>Conditional Rendering</strong></li>
</ol>
<p>This strategy dynamically involves importing and rendering components only when a specific user interaction or condition is met. This is particularly useful for features that are not immediately visible or essential on page load, such as models, accordions, and video players that only active on a click.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> VideoPlayer = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/VideoPlayer'</span>));
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">VideoSection</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> setShowPlayer(<span class="hljs-literal">true</span>)}&gt;Play Video&lt;/button&gt;
      {<span class="hljs-comment">/* VideoPlayer component is only loaded and rendered when showPlayer is true */</span>}
      {showPlayer &amp;&amp; &lt;VideoPlayer /&gt;}
    &lt;/div&gt;
  );
}
</code></pre>
<p>In this example, the <code>VideoPlayer</code> component's code is only downloaded and rendered when users click a “Play Video“ button. This prevents the browser from downloading a potentially large video player library until the user explicitly requests the functionality.</p>
<ol start="3">
<li><strong>Intersection Observe API</strong></li>
</ol>
<p>The Intersection Observe API provides a performant way to detect when an element enters or exits the viewport. This is ideal for lazy loading components that are “below-the-fold“ (not immediately visible on the screen) or for implementing infinity scrolling patterns. By loading components when they are about to become visible, you can significanly reduce the initil load time and resource comsumption.</p>
<pre><code class="lang-typescript"><span class="hljs-string">'use client'</span>; <span class="hljs-comment">// This component uses browser APIs and React Hooks</span>

<span class="hljs-keyword">import</span> { useEffect, useRef, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>;
<span class="hljs-keyword">const</span> Reviews = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'../components/Reviews'</span>));
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ReviewsSection</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> ref = useRef(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [isVisible, setIsVisible] = useState(<span class="hljs-literal">false</span>);
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(<span class="hljs-function">(<span class="hljs-params">[entry]</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (entry.isIntersecting) {
        setIsVisible(<span class="hljs-literal">true</span>);
        observer.disconnect(); <span class="hljs-comment">// Stop observing once the component is visible and loaded</span>
      }
    });
    <span class="hljs-keyword">if</span> (ref.current) observer.observe(ref.current);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> observer.disconnect(); <span class="hljs-comment">// Clean up observer on unmount</span>
  },);
  <span class="hljs-keyword">return</span> (
    &lt;div ref={ref}&gt;
      {<span class="hljs-comment">/* Reviews component is only loaded and rendered when it becomes visible in the viewport */</span>}
      {isVisible &amp;&amp; &lt;Reviews /&gt;}
    &lt;/div&gt;
  );
}
</code></pre>
<p>Here, the <code>Reviews</code> component is dynamically loaded only when its containing <code>div</code> (referenced by <code>ref</code>) enters the user's viewport. This is the common pattern for sections like customer reviews, comments, or image galleries that appear further down a page.</p>
<ol start="4">
<li><strong>Route-Based Code Splitting</strong></li>
</ol>
<p>Next.js inherently optimizes performance through automatic route-based code splitting. This means that each page (or route) on your application is automatically split into its own independent JavaScript bundle. For example, the JavaScript for</p>
<p><code>pages/about.tsx</code> (or <code>app/about/page.tsx</code> in the App Router, it is only loaded when the <code>/about</code> route is accessed.</p>
<p>This automatic behavior is a significant advantage, as it ensures that users only download the code necessary for the specific pages they are viewing, rather than a monolithic bundle containing the entire application’s JavaScript. This leads to faster initial page loads and improved overall performance.</p>
<p>Tips: To maximize the benefits of route-based code splitting, avoid importing large libraries or components globally (e.g., in <code>_app.tsx</code> or a root layout in the App Router) unless they are truly essential for every single page of your application. Global imports can negate the advantages of code splitting by forcing unnecessary code into every page’s initial bundle.</p>
<ol start="5">
<li><strong>Lazy Loading Third-Party Scripts</strong></li>
</ol>
<p>Third-party scripts, such as analytics trackers, advertising scripts, or social media embeds, can often be significant performance bottlenecks. They can block the main thread, delay rendering, and natively impact Core Web Vitals. Next.js provides the <code>next/script</code> component to give you fine-grained control over when and how these external scripts are loaded, preventing them from hindering your application’s performance.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> Script <span class="hljs-keyword">from</span> <span class="hljs-string">'next/script'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      {<span class="hljs-comment">/* This script will load during the browser's idle time, after the page is interactive */</span>}
      &lt;Script
        src=<span class="hljs-string">"https://example.com/analytics.js"</span>
        strategy=<span class="hljs-string">"lazyOnload"</span>
      /&gt;
      &lt;p&gt;Page content&lt;/p&gt;
    &lt;/&gt;
  );
}
</code></pre>
<p><strong>Strategies Available with</strong> <code>next/script</code><strong>:</strong></p>
<ul>
<li><p><code>strategy="beforeInteractive"</code>: This loads the script before the page becomes interactive (before hydration). Use this for scripts that are critical for the page's initial functionality or appearance, but still need to be loaded by Next.js.</p>
</li>
<li><p><code>strategy="afterInteractive"</code>: This loads the script after the page has become interactive (after React has hydrated the page). This is a good default for most non-critical scripts that don't need to block the initial render.</p>
</li>
<li><p><code>strategy="lazyOnload"</code>: This defers the loading of the script until the browser's idle time, after the page has fully loaded and become interactive. This is ideal for scripts that are not essential for the core user experience, such as analytics or chat widgets.</p>
</li>
</ul>
<p>By choosing the appropriate loading strategy, you can prevent third-party scripts from negatively impacting your site’s initial load and interactivity.</p>
<p><strong>Real-world example:</strong> On an e-commerce site, we had a hefty product comparison feature (with a big library) that was initially loading on every product page, though the user rarely used it. We changed it to load dynamically only when the user clicks “Compare”. This removed ~100 KB from the product page bundle. The immediate effect was that he product pages loaded about 30% faster and FID improved because less JS was executed upfront. Users who needed the compare feature experienced a slight delay <em>only when they invoked it</em>, which is a fair trade-off. Overall engagement went up as more users stayed (fast content drew them in, and by the time they clicked compare, the chunk was loaded or in progress).</p>
<p>Another scenario: imagine a blog site with an interactive comments widget that loads below the article. By splitting the comments component (and maybe even using an <code>&lt;IntersectionObserver&gt;</code> to preload it when the user scrolls near), the initial article content loads faster (good LCP), and the comments JS only loads if the user is going to see it. Users who just read and leave aren’t penalized by that extra JS.</p>
<p><strong>Bottom line:</strong> <em>“Users only download the necessary modules.”</em> for what they are doing right now. This keeps the app fast and responsive. Next.js makes it easy with dynamic imports, so identify parts of your app are lazy-loaded and implement them. Monitor your webpack bundle analysis before and after — you should see certain chunks carved out. Also, test the user experience to ensure the loading states are acceptable (provide a nice spinner and skeleton if needed). When done right, users won’t even notice that parts of your app are loaded on demand; they will just feel the app is fast.</p>
<h3 id="heading-leverage-edge-functions-and-cdn-for-low-ttfb">Leverage Edge Functions and CDN For Low TTFB</h3>
<p>If your Next.js app is global (most of these days), one way to speed up responses is to run your code as code as possible to the user. Edge Functions allows you to deploy the server-side logic to data centers around the world, reducing latency and improving Time To First Byte (TTFB). Next.js on Vercel supports edge runtimes (for middlewares or API routes) that run on Vercel’s Edge Network, and similarly, you can deploy on Cloudflare Workers. The ideal is to avoid that slow transoceanic round trip for each request.</p>
<p>Think of Edge Functions as your “mini servers“ distributed worldwide. Instead of a user from Asia having to hit a server from North America (taking hundreds of milliseconds for distance), the request can be handled in Asia as well. As one developer described: “When logic executes close to the user, the TTFB drops significantly. Imagine a user in Singapore hitting an API request to a server in Northern Virginia — that round-trip is brutal. With Edge Functions, the request is handled in Singapore itself*: Lower TTFB, better FCP, and happier users.*“</p>
<p><strong>Ways to use edge in Next.js:</strong></p>
<ul>
<li><p><strong>Edge Runtime API Routes:</strong> You can create a file under <code>pages/api</code> or the new App Router’s route handlers, and export <code>config = { runtime: 'edge' }</code>. This will deploy that function to the edge. Use it for things like personalization, geolocation-based content, authentication checks, etc., where responding quickly is crucial.</p>
</li>
<li><p><strong>Middleware:</strong> Next.js middleware (under <code>middleware.js</code>) always runs at the edge by default. Use it for redirecting or rewriting on the fly with virtually no latency hit, since it runs close to the user.</p>
</li>
<li><p><strong>Cache and static assets on CDN:</strong> Next.js automatically serves static files (including static pages) via CDN. Ensure you take advantage of this by using <code>getStaticProps</code>/<code>getStaticPaths</code> or the App Router’s <code>fetch</code> caching and revalidation settings. Static assets should be CDN-served so that a user in London gets the file from a European server, one in New York gets it from US East, etc. This happens by default on platforms like Vercel.</p>
</li>
</ul>
<p>By using edge functions and globally distributed caching, you’ll improve not just TTFB but often other metrics like FCP (first paint) since initial HTML arrives sooner. It also allows for dynamic content that’s still fast. For example, you can personalize content at the edge (e.g., show region-specific promos, or the user’s name if logged in) without a slow origin fetch. One can <em>“inject personalization at the edge without slowing down client-side load”</em>, achieving fast dynamic pages with no hydration jank<a target="_blank" href="https://dev.to/hasunnilupul/the-impact-of-edge-functions-on-frontend-performance-1lde#:~:text=2">dev.to</a>.</p>
<p><strong>Real-world story:</strong> A startup had its Next.js app deployed on a single region. Users far from that region experienced TTFB of 500ms to 1s. After migrating key APIs to edge functions and enabling full page caching on the edge for public pages, global users saw TTFB drop to ~100–200ms. For instance, a user in India got a response from a Mumbai edge node in 100ms, whereas before it was ~700ms from a US server. This shaved significant time off the <strong>First Contentful Paint</strong> as well — the content started arriving faster. Core Web Vitals improved; for example, faster TTFB contributed to an FCP improvement on slow 3G connections by nearly 30%. Edge functions essentially acted as a <strong>frontend performance multiplier</strong>, as one article put it<a target="_blank" href="https://dev.to/hasunnilupul/the-impact-of-edge-functions-on-frontend-performance-1lde#:~:text=Edge%20functions%20are%20more%20than,to%20users%20across%20the%20globe">dev.to</a>, by bringing server-side rendering closer to users.</p>
<p><strong>Note:</strong> Edge functions do have some limitations (no full Node.js environment, and cold starts, though typically very small). Use them for the performance-critical path, and test under load. The payoff is worth it when your audience is globally distributed. If using Vercel, also consider their <strong>Edge Middleware and Edge Config</strong> for quick data lookups at the edge (like feature flags or A/B tests) without back-and-forth to the origin.</p>
<p>In summary, <strong>run your app at the edge and cache wisely</strong>. It lowers latency, yielding snappier interactions. “If you’re serious about slashing TTFB and building experiences that feel instant, edge functions are a must in your stack.”.</p>
<h3 id="heading-pre-render-and-cache-as-much-as-possible-ssr-isr-and-partial-prerendering">Pre-Render and Cache as Much as Possible (SSR, ISR, and Partial Prerendering)</h3>
<p>Fetching data and rendering on every request can be expensive and slow. Whenever feasible, let Next.js <strong>pre-render pages or parts of pages ahead of time</strong> and serve them from cache. Next.js 15 provides a spectrum of rendering strategies: <em>Static Site Generation (SSG)</em> for fully static pages, <em>Incremental Static Regeneration (ISR)</em> for updating static pages periodically, and now <strong>Partial Prerendering</strong> for a hybrid approach where some parts are static and others are dynamic. Using these wisely can give you the best of both worlds: <strong>fast, cached content plus freshness</strong>.</p>
<p><strong>Static pre-rendering:</strong> If a page’s content can be generated at build time (or even on a schedule), do it! A static page served from a CDN is about as fast as it gets (nearly zero TTFB). Next.js supports SSG via <code>getStaticProps</code>. In the Next 15 App Router, you can achieve similar behavior with the <code>fetch</code> API by using <code>cache: 'force-cache'</code> (for truly static data) or <code>revalidate</code> options for ISR. For example, an e-commerce product page could prerender product details statically and revalidate every hour, so most users get a cached page, and once an hour it updates with any changes. This drastically reduces the load on your servers and speeds up the response.</p>
<p><strong>Partial Prerendering:</strong> A new concept in Next.js 15 is the ability to <strong>selectively prerender parts of a page</strong>. As the Next.js team describes it, <em>“Partial Pre-rendering improves performance by selectively pre-rendering only essential parts of your page during build, while dynamic content loads progressively when needed.”</em>. For instance, you might prerender a blog post's content (which changes rarely) but not prerender the comments section (which is dynamic); that dynamic part can load client-side or via SSR. The initial HTML contains the important stuff, giving a fast LCP, and the rest comes in after. This approach was shown to <strong>improve Core Web Vitals like TTFB and LCP</strong> in Next.js Conf demos. Essentially, users see the main content quickly, and any live-updating portions stream in.</p>
<p>To use partial prerendering in App Router, you can combine static and dynamic segments in your page. One method is using the <code>Suspense</code> pattern as shown in a Next 14 example<a target="_blank" href="https://dev.to/hijazi313/nextjs-14-performance-optimization-modern-approaches-for-production-applications-3n65#:~:text=Next,content%20rendering%20for%20optimal%20performance">dev.to</a><a target="_blank" href="https://dev.to/hijazi313/nextjs-14-performance-optimization-modern-approaches-for-production-applications-3n65#:~:text=%7B%2F,div%3E%20%29%3B">dev.to</a>: render <code>&lt;StaticDashboardMetrics /&gt;</code> (no suspense, so prerendered) and wrap <code>&lt;UserActivity /&gt;</code> in <code>&lt;Suspense&gt;</code> so it’s fetched at request time. The static parts are built once, and the dynamic part can be SSR or even client-side. This yields an <em>instant static shell</em> with dynamic data loading after boosting perceived performance significantly.</p>
<p><strong>Caching on the server:</strong> Next.js 15 also gives fine-grained control with the new <code>caches</code>. You can designate certain fetches to use <code>force-cache</code> (always cache) or <code>no-store</code> (always live) or timed revalidation. For example, <code>fetch(url, { next: { revalidate: 60 } })</code> in a Server Component will cache that request for 60 seconds. Use this to cache API responses and avoid re-fetching on every request. Cached responses = faster responses.</p>
<p><strong>Use a CDN for static assets and pages:</strong> Deployed on platforms like Vercel, your static pages (SSG) and public assets automatically get served via a global CDN. Ensure cache headers are set so that repeat visits are blazing fast (and consider using service workers or <code>next/pwa</code> if you want aggressive client-side caching for repeat visits.</p>
<p><strong>Example transformation:</strong> A content site with mostly article pages moved from SSR (rendering each request) to ISR with a 5-minute revalidate. Most users then got a static cached page from the nearest edge. The TTFB for those pages dropped from ~800ms (SSR from origin) to ~100ms (cached HTML), and LCP improved because the browser was getting HTML almost immediately. Even when data updates frequently, caching for even a short duration (like 60 seconds) can absorb a lot of traffic and speed up responses for the majority of users. Another example: a dashboard used partial prerendering — it prerendered the layout and static widgets, and SSR’d the user-specific data. The initial paint (with the static content) happened in ~1s, whereas before, the whole thing took ~2.5s to render fully. Users saw <em>something</em> useful very quickly and perceived it as faster, even though some data was still loading.</p>
<p><strong>Bottom line:</strong> Don’t generate content on the fly if you don’t need to. Pre-generate it, cache it, and serve it like static whenever possible. Next.js gives you the tools to do this at a granular level (down to per-request or per-component caching). Use <strong>ISR</strong> for things that can be slightly stale. Use <strong>full SSG</strong> for truly static content. And with <strong>partial prerendering</strong>, carve out a static skeleton for dynamic pages. This reduces server load and massively improves scalability and performance. As one blog said about Next 15: partial prerendering delivers <em>“instant static content while dynamically loading personalized elements, significantly improving TTFB and LCP.”</em>. Exactly what we want!</p>
<h3 id="heading-monitor-performance-continuously-with-the-right-tools">Monitor Performance Continuously with the Right Tools</h3>
<p>You can’t improve what you don’t measure. To ensure your Next.js app remains lightning fast, you should continuously <strong>monitor performance metrics</strong> and catch regressions early. Thankfully, there are excellent tools for both lab and real-user measurements that you can integrate into your workflow.</p>
<p>Here are some recommended tools and how to use them:</p>
<ul>
<li><p><strong>Lighthouse CI:</strong> Google’s Lighthouse (as in Chrome DevTools Audits or PageSpeed Insights) provides lab performance tests. Using <strong>Lighthouse CI</strong> in your continuous integration pipeline can automatically run performance audits on every build or pull request. Set up a budget (e.g., FCP under 2s, LCP under 2.5s, bundle size under X KB), and Lighthouse CI can fail the build if a change introduces a significant slowdown. This ensures performance is monitored just like tests are. <em>Start with basic Lighthouse checks in CI and gradually add more custom metrics as your team gets comfortable</em>. Over time, you can enforce stricter budgets — e.g., if a developer adds a heavy library, you’ll know before it hits production.</p>
</li>
<li><p><strong>Vercel Analytics:</strong> If you’re deploying on Vercel, their Analytics feature provides <strong>real user monitoring</strong> of Core Web Vitals. It inserts a tiny script to measure actual LCP, FID, etc. from your users and reports to a dashboard. The great thing is it gives you a <strong>Real Experience Score (RES)</strong> — an aggregate of your site’s performance as experienced by real users. This lets you catch if maybe users on certain devices or regions are slow, or if a new release hurts performance in the field. Unlike lab tests, this is actual data from real sessions. You can use this in combination with Google’s CrUX data or your own analytics.</p>
</li>
<li><p><strong>Chrome DevTools &amp; Performance Tab:</strong> For local profiling and deep dives, nothing beats running your app in Chrome (or Edge) and recording with the Performance tab. This shows you every task on the main thread, paint timings, script evaluations, etc. It’s excellent for diagnosing <em>why</em> a certain interaction is slow or what’s blocking the main thread. For example, the Performance tab can reveal a long task that causes a 300ms input delay. Our team often uses it to pinpoint exactly which function or component is a hotspot. As one CTO said, it went from intimidating to an <em>indispensable tool</em> once you learn to read the flame charts. Use it during development to fine-tune.</p>
</li>
<li><p><strong>WebPageTest:</strong> This is a powerful tool for synthetic testing, especially for simulating <strong>slow networks or devices</strong>. You can run a test from various locations and throttle the connection (e.g., 3G or Slow 4G) to see how your site performs under less-than-ideal conditions. WebPageTest gives incredibly detailed waterfall charts, filmstrip views of rendering, and core vital measurements. It’s great to test a production deployment and see, for example, how the LCP behaves, which resources are loading late, etc. Many teams use WebPageTest for spot checks or integration with performance budgets (there’s an API and even GitHub actions).</p>
</li>
<li><p><strong>Google Analytics (GA4) or custom telemetry:</strong> GA4 can track Web Vitals as well (with some custom code or plugins). Alternatively, there are specialized services (SpeedCurve, Calibre, DebugBear, etc.) that continuously monitor your site’s performance from multiple regions. These can alert you if, say, LCP degrades beyond a threshold.</p>
</li>
</ul>
<p>In the Next.js context, you can also use the built-in <code>reportWebVitals</code> function. Next.js allows you to export a <code>reportWebVitals(metric)</code> in your app, which will get called with each web vital (if you have Analytics disabled or want to send to your own endpoint). You could use this to send data to an analytics service of your choice.</p>
<p><strong>Make performance monitoring a habit:</strong> Set up dashboards visible to the team, so everyone can see current perf scores. Perhaps have a weekly check-in on performance budgets. A culture of performance means issues get caught and fixed early. For example, if a code change accidentally adds 100KB to your bundle and slows down FID, a Lighthouse CI budget failure, or a jump in Vercel Analytics’ RES will alert you, and you can address it before it impacts all users<a target="_blank" href="https://pagepro.co/blog/5-lessons-for-next-js-performance-optimization-in-large-projects/#:~:text=1,automatically%20flag%20when%20they%E2%80%99re%20exceeded">pagepro.co</a><a target="_blank" href="https://vercel.com/blog/core-web-vitals#largest-contentful-paint#:~:text=Vercel%20Analytics%20%20takes%20Lighthouse,Web%20Vitals%20your%20users%20experience">vercel.com</a>.</p>
<p><strong>Case study:</strong> Our team introduced performance budgets in CI for a Next.js project. One day, a dependency update caused the bundle to grow unexpectedly, and Lighthouse CI flagged that the performance score dropped from 95 to 88. Investigating, we found the culprit (a misconfigured polyfill). We fixed it before merging to main. Without these tools, we might not have noticed until users complained or analytics showed a slowdown. That safety net is invaluable.</p>
<p>In summary, use <strong>lab tools</strong> (Lighthouse, WebPageTest, DevTools) to optimize in controlled environments, and <strong>field tools</strong> (Vercel Analytics, real-user metrics) to ensure real users are getting the experience you expect. Combine that with automation (CI checks, alerts) so you maintain your hard-earned optimizations over time. As the saying goes, <em>“performance is a journey, not a destination.”</em> Continuous monitoring will keep you on the right track.</p>
<h3 id="heading-build-a-performance-first-mindset-apply-to-all-types-of-apps">Build a Performance-First Mindset (Apply to all types of apps)</h3>
<p>Our final tip is a bit more holistic: cultivate a <strong>performance-first mindset</strong> throughout your development process. Next.js gives you many tools, but it’s up to the team to use them effectively and prioritize performance from the start. This tip ties everything together and ensures that, whether you’re building an e-commerce site, a SaaS application, or a content hub, you consistently apply these optimizations as second nature.</p>
<p><strong>What does a performance-first mindset look like?</strong></p>
<ul>
<li><p><strong>Plan for performance from day one:</strong> When designing features, consider the performance implications. For example, if you’re adding a new image-heavy section, plan to use Next/Image and perhaps lazy load it. If you’re integrating a third-party script (analytics, ads, etc.), consider its cost and how to mitigate it (maybe load after user interaction or on idle).</p>
</li>
<li><p><strong>Establish performance budgets &amp; goals:</strong> Set concrete goals (e.g., LCP &lt; 2s on median mobile, FID &lt; 100ms, etc.). Having targets makes it easier to make decisions (you might decide against a fancy but heavy library if it would break the budget). Many teams include these in requirements, just like functionality.</p>
</li>
<li><p><strong>Everyone on the team owns performance:</strong> It’s not just for one “performance engineer” — developers, designers, and product managers all should value it. For instance, designers should know that huge background videos might hurt performance; developers should review each other’s code for potential bloat or inefficiencies. As one company put it, they created a <strong>performance-first culture</strong> where performance is a shared responsibility and part of the definition of done.</p>
</li>
<li><p><strong>Regularly audit and learn:</strong> The web evolves, and so do best practices. Make time for periodic performance audits of your Next.js app. This could be as simple as scheduling a monthly deep dive where you profile the app and see if any regressions or new opportunities have arisen. Also, encourage team knowledge sharing — if someone learned a new trick (like a new Next.js feature or React optimization), share it with everyone.</p>
</li>
<li><p><strong>Use the latest Next.js features:</strong> Next.js 15+ is introducing things like stable Turbopack, enhanced React 19 features, etc., which often come with perf benefits. Keep your Next.js version up to date (within reason) and read release notes for anything that could help performance. For example, if Next 15.2 announces an improved <code>&lt;Image&gt;</code> or better hydration technique, consider adopting it.</p>
</li>
</ul>
<p>A quick example of applying this mindset: Let’s say you’re tasked with building a new <strong>pricing page</strong> for a SaaS app. With a performance-first approach, you would: optimize all images (maybe use SVG for logos, Next/Image for others), ensure the page is static (SSG) since pricing doesn’t change often, maybe use partial hydration if there’s a dynamic calculator widget (so the static content loads immediately), test it on slow network to ensure it’s under budget, and perhaps set up a Lighthouse CI threshold from the start for it. The result is a page that not only looks good but is technically optimized from day one, requiring no retroactive fixes.</p>
<p>Teams that do this find that performance isn’t an afterthought or a one-off project — it’s just part of building the app. When new team members join, they see that pull requests include discussions about bundle size or using the correct Next.js features, and they adopt the same approach.</p>
<p>Finally, remember that <strong>performance benefits everyone</strong>: it improves accessibility (fast sites work better on low-end devices), it pleases users (nobody ever said “I love how slow this site is!”), and it drives business metrics (better SEO, more engagement). So it’s absolutely worth the investment.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this article, we have covered several advanced Next.js concepts. By mastering these concepts, you will be able to build powerful, performant web applications with Next.js. Whether you are building a small blog or a large-scale e-commerce platform, Next.js has the tools and features you need to deliver a seamless user experience.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://www.freecodecamp.org/news/nextjs-vs-react-differences/">https://www.freecodecamp.org/news/nextjs-vs-react-differences/</a></p>
<p><a target="_blank" href="https://mrizkiaiman.medium.com/understanding-next-js-rendering-strategies-2023-ssr-csr-ssg-isr-9ffb792cf757">https://mrizkiaiman.medium.com/understanding-next-js-rendering-strategies-2023-ssr-csr-ssg-isr-9ffb792cf757</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/next-js-client-side-rendering-56a3cae65148">https://javascript.plainenglish.io/next-js-client-side-rendering-56a3cae65148</a></p>
<p><a target="_blank" href="https://blog.devgenius.io/advanced-next-js-concepts-8439a8752597">https://blog.devgenius.io/advanced-next-js-concepts-8439a8752597</a></p>
<p><a target="_blank" href="https://blog.stackademic.com/you-must-use-middleware-like-this-in-next-js-64d59bb4cd59">https://blog.stackademic.com/you-must-use-middleware-like-this-in-next-js-64d59bb4cd59</a></p>
<p><a target="_blank" href="https://yohanlb.hashnode.dev/when-should-i-use-server-action-nextjs-14?ref=dailydev">https://yohanlb.hashnode.dev/when-should-i-use-server-action-nextjs-14?ref=dailydev</a></p>
<p><a target="_blank" href="https://medium.com/@sanjeevanibhandari3/how-i-made-my-next-js-app-load-10x-faster-and-you-can-too-30a8b6c86d9c">https://medium.com/@sanjeevanibhandari3/how-i-made-my-next-js-app-load-10x-faster-and-you-can-too-30a8b6c86d9c</a></p>
<p><a target="_blank" href="https://aryalskanda1.medium.com/5-tips-and-tricks-to-make-your-life-with-next-js-14-easier-f272bb52537e">https://aryalskanda1.medium.com/5-tips-and-tricks-to-make-your-life-with-next-js-14-easier-f272bb52537e</a></p>
<p><a target="_blank" href="https://marcoscamara.medium.com/stop-calling-next-js-slow-master-these-optimization-techniques-7cfc1cfbb3df">https://marcoscamara.medium.com/stop-calling-next-js-slow-master-these-optimization-techniques-7cfc1cfbb3df</a></p>
<p><a target="_blank" href="https://blog.devgenius.io/10-powerful-next-js-optimization-tips-f78288d284e1">https://blog.devgenius.io/10-powerful-next-js-optimization-tips-f78288d284e1</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/next-js-hates-me-until-i-made-it-10x-faster-cae6d1b65876">https://javascript.plainenglish.io/next-js-hates-me-until-i-made-it-10x-faster-cae6d1b65876</a></p>
<p><a target="_blank" href="https://medium.com/yopeso/a-year-with-next-js-server-actions-lessons-learned-93ef7b518c73">https://medium.com/yopeso/a-year-with-next-js-server-actions-lessons-learned-93ef7b518c73</a></p>
<p><a target="_blank" href="https://medium.com/gitconnected/when-to-use-react-query-with-next-js-server-components-f5d10193cd0a">https://medium.com/gitconnected/when-to-use-react-query-with-next-js-server-components-f5d10193cd0a</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/nextjs-image-performance-issues-and-fixes-40db2061ffe1">https://levelup.gitconnected.com/nextjs-image-performance-issues-and-fixes-40db2061ffe1</a></p>
<p><a target="_blank" href="https://blog.stackademic.com/what-use-client-really-does-in-react-and-next-js-1c0f9651c4e1">https://blog.stackademic.com/what-use-client-really-does-in-react-and-next-js-1c0f9651c4e1</a></p>
<p><a target="_blank" href="https://medium.com/@sureshdotariya/next-js-15-app-router-architecture-and-sequence-flow-3a6ffdd2445c">https://medium.com/@sureshdotariya/next-js-15-app-router-architecture-and-sequence-flow-3a6ffdd2445c</a></p>
<p><a target="_blank" href="https://medium.com/@sureshdotariya/10-proven-ways-to-make-your-next-js-app-lightning-fast-in-2025-18acb8a62e5f">https://medium.com/@sureshdotariya/10-proven-ways-to-make-your-next-js-app-lightning-fast-in-2025-18acb8a62e5f</a></p>
<p><a target="_blank" href="https://semaphoreci.medium.com/cache-optimization-on-nextjs-without-vercel-c5927177ea02">https://semaphoreci.medium.com/cache-optimization-on-nextjs-without-vercel-c5927177ea02</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/cutting-redundant-data-fetches-with-reacts-cache-in-react-19-949ca6c5e364">https://javascript.plainenglish.io/cutting-redundant-data-fetches-with-reacts-cache-in-react-19-949ca6c5e364</a></p>
<p><a target="_blank" href="https://medium.com/@sanjeevanibhandari3/how-to-fix-the-most-annoying-hydration-errors-in-next-js-0b3ce36c5528">https://medium.com/@sanjeevanibhandari3/how-to-fix-the-most-annoying-hydration-errors-in-next-js-0b3ce36c5528</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/next-js-middleware-explained-3-real-world-use-cases-with-code-snippets-792dc3d2bc15">https://javascript.plainenglish.io/next-js-middleware-explained-3-real-world-use-cases-with-code-snippets-792dc3d2bc15</a></p>
]]></content:encoded></item><item><title><![CDATA[🔥 All The New Features In React]]></title><description><![CDATA[React’s journey began in 2011 when Facebook engineers created it to manage the increasingly complex interface of their rapidly growing platform. React’s initial focus was on re-rendering only the necessary parts of the UI, leading to improved perform...]]></description><link>https://blog.tuanhadev.tech/all-the-new-features-in-react</link><guid isPermaLink="true">https://blog.tuanhadev.tech/all-the-new-features-in-react</guid><category><![CDATA[React]]></category><category><![CDATA[React 19]]></category><category><![CDATA[react 18]]></category><category><![CDATA[#newfeatures]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[react server components]]></category><category><![CDATA[server actions]]></category><category><![CDATA[hooks]]></category><category><![CDATA[context API]]></category><category><![CDATA[Server side rendering]]></category><category><![CDATA[learn react]]></category><category><![CDATA[React 17]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Sat, 04 Jan 2025 09:46:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/ukzHlkoz1IE/upload/d3414143d6c66d039fc299f4a7570926.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>React’s journey began in 2011 when Facebook engineers created it to manage the increasingly complex interface of their rapidly growing platform. React’s initial focus was on re-rendering only the necessary parts of the UI, leading to improved performance and smoother user experiences. Over the years, React has evolved significantly, incorporating new features like Hooks, concurrent rendering, and server-side rendering.</p>
<p>Today, we will list those new features together over several updates to React.</p>
<p>Let’s get started!!!!</p>
<h1 id="heading-react-19">React 19</h1>
<p>The release of React 19 brings a host of exciting new features and updates that enhance developer productivity, offer performance, and provide greater flexibility.</p>
<h2 id="heading-automatic-memoization">Automatic Memoization</h2>
<p>Do you remember React Forget, introduced by Huang Xuan at React Conf 2021?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735723830799/a4b4cee9-7b44-4e93-b040-a7b1b0e4cc0d.webp" alt class="image--center mx-auto" /></p>
<p>Now, it’s here.</p>
<p>It’s a compiler that has been already applied in Instagram’s production environment. The React team plans to apply it in more platforms within Meta and will make it open-source in the feature.</p>
<p>Before using the new compiler, we used <code>useMemo</code>, <code>useCallback</code>, and <code>memo</code> to manually cache states to reduce unnecessary re-renders. Although this implementation is feasible, the React team believes it is not the ideal way they envision. They have been looking for a solution that allows React to automatically and only re-render the necessary parts when the state changes. After years of effort, the new compiler has successfully landed.</p>
<p>The new React compiler will be an out-of-the-box feature, representing another paradigm shift for developers. This is the most anticipated feature of v19.</p>
<p>Interestingly, the React team did not mention “React Forget“ when introducing the new React compiler, which led to a humorous comment from the community: They forget React Forget &amp; forget to mention Forget in the Forget section 😂</p>
<h2 id="heading-how-react-compiler-performs-on-real-code">How React Compiler performs on real code</h2>
<p>In the last few years, one of the biggest sources of excitement and anticipation in the React community has been a tool known as React Compiler (previously React Forget). And for a good reason, the central premise of the compiler is that it will improve the overall performance of our React applications. As a nice consequence, we will never have to worry about re-renders, memorization, and <code>useMemo</code> and <code>useCallback</code> hooks.</p>
<p>But what’s the problem with React’s performance in the first place? And why do half of the devs desperately want to forget about memorization and those hooks? And how realistic in this promise?</p>
<h3 id="heading-the-problem-of-re-renders-and-memorization-in-react">The problem of re-renders and memorization in React?</h3>
<p>So, what exactly is the problem here?</p>
<p>Most of the React apps out there are written to show some interactive UI (User Interface) to the user. When the user interacts with the UI, we usually want to update the page with some new information derived from that interaction. To do this in React, we trigger what is known as re-renders.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*rSU6XDavZDZhj4U4.png" alt /></p>
<p>Re-renders in React normally are cascading. Every time a re-render of a component is triggered, it triggers a re-render of every nested component inside, and so on and so forth, until the end of the React components is reached.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*UdCfBcAmxvn7y3XY.gif" alt /></p>
<p>Normally, this is not something to worry about — React is pretty fast these days. However, if those downstream re-renders affect some heavy components or components that just re-render too much, this might cause performance problems. This app will become slow.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*HQA863xC2iFJ0Cqs.png" alt /></p>
<p>One way to fix this slowness is to stop the chain of re-renders from happening.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*xwqJfOqLuy79dp04.png" alt /></p>
<p>We have multiple techniques to do that, <a target="_blank" href="https://www.developerway.com/posts/react-re-renders-guide#part3.2">moving state down</a>, <a target="_blank" href="https://www.developerway.com/posts/react-re-renders-guide#part3.3">passing components as props</a>, extracting state into a Context-like solution to bypass props drilling, to name a few. And memorization, of course.</p>
<p>Memorization starts with <a target="_blank" href="https://react.dev/reference/react/memo">React.memo</a> — a higher-order component was given to us by the React team. To make it work, all we need to do is wrap our original component with it and render the “memoized“ version in its place.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// memoize a slow component here</span>
<span class="hljs-keyword">const</span> VerySlowComponentMemo = React.memo(VerySlowComponent);

<span class="hljs-keyword">const</span> Parent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// trigger re-render somewhere here</span>

  <span class="hljs-comment">// render the memoized component in place of the original</span>
  <span class="hljs-keyword">return</span> &lt;VerySlowComponentMemo /&gt;;
};
</code></pre>
<p>Now, when React reaches this component in the tree, it will stop and check whether its props have changed. If one of the props changes, the re-renders will be stopped. However, if even one single prop has changed, React will continue with its re-renders as if no memorization had happened.</p>
<p>That means that for the memo to work properly, we need to make sure that all props stay exactly the same between the re-renders.</p>
<p>For primitive values, like strings and booleans, it’s easy; we don’t need to do anything other than just not changing those values.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> VerySlowComponentMemo = React.memo(VerySlowComponent);

<span class="hljs-keyword">const</span> Parent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// trigger re-render somewhere here</span>

  <span class="hljs-comment">// "data" string between re-renders stays the same</span>
  <span class="hljs-comment">// so memoization will work as expected</span>
  <span class="hljs-keyword">return</span> &lt;VerySlowComponentMemo data=<span class="hljs-string">"123"</span> /&gt;;
};
</code></pre>
<p>Non-primitive values, like objects, arrays, and functions, however, need some help.</p>
<p>React uses referential <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness">equality</a> to check for anything between re-renders. So, if we declare those non-primitives inside the component, they will be re-created on every re-render, reference to them will change and memorization won’t work.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> VerySlowComponentMemo = React.memo(VerySlowComponent);

<span class="hljs-keyword">const</span> Parent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// trigger re-render somewhere here</span>

  <span class="hljs-comment">// "data" object is re-created with every re-render</span>
  <span class="hljs-comment">// memoization is broken here</span>
  <span class="hljs-keyword">return</span> &lt;VerySlowComponentMemo data={{ id: <span class="hljs-string">"123"</span> }} /&gt;;
};
</code></pre>
<p>To fix this, we have two hooks: <code>useMemo</code> and <code>useCallback</code>. Both of those will preserve the reference between re-renders. <code>useMemo</code> is typically used with objects and arrays, and <code>useCallback</code> with functions. Wrapping props into those hooks is what we usually know as "memoizing props".</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Parent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// reference to { id:"123" } object is now preserved</span>
  <span class="hljs-keyword">const</span> data = useMemo(<span class="hljs-function">() =&gt;</span> ({ id: <span class="hljs-string">"123"</span> }), []);
  <span class="hljs-comment">// reference to the function is now preserved</span>
  <span class="hljs-keyword">const</span> onClick = useCallback(<span class="hljs-function">() =&gt;</span> {}, []);

  <span class="hljs-comment">// props here don't change between re-renders anymore</span>
  <span class="hljs-comment">// memoization will work correctly</span>
  <span class="hljs-keyword">return</span> (
    &lt;VerySlowComponentMemo
      data={data}
      onClick={onClick}
    /&gt;
  );
};
</code></pre>
<p>Now, when React encounters the <code>VerySlowComponentMemo</code> component in the render tree, it will check whether its props have changed, will see that none of them have, and will skip its re-renders. The app is not slow anymore.</p>
<p>This is a very simplified explanation, but it’s quite complex already. To make the situation even worse, if we pass those memorized props through a chain of components, it becomes even more complicated; any change to them would require tracing those chains back and forth to make sure the reference is not lost in between.</p>
<p>As a result, it’s easier just not to do it at all or memorize everything everywhere just in case. Which, intern, turns our beautiful code into a comprehensible and unreadable of <code>useMemo</code> and <code>useCallback</code>.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:1400/0*8d5pN0Wk9_UsrmCm.png" alt /></p>
<p>Solving this situation is the main promise of React’s Compiler.</p>
<h3 id="heading-react-compiler-to-the-rescue">React Compiler to the rescue</h3>
<p><a target="_blank" href="https://react.dev/learn/react-compiler">React Compiler</a> is a Babel plugin developed by the React core team, with the <a target="_blank" href="https://react.dev/blog/2024/10/21/react-compiler-beta-release">Beta version released</a> in October 2024.</p>
<p>During build time, it tries to convert the “normal“ React code into the code where components, their props, and the dependencies of hooks are memoized by default. The end result is the “normal“ React code that behaves as if everything is wrapped in <code>memo</code>, <code>useMemo,</code> and <code>useCallback</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747555077389/9dc83880-785b-4b5e-a63f-1f931f8ad852.webp" alt class="image--center mx-auto" /></p>
<p>Almost! In reality, it does many more complicated conversions and tries to adjust to the code as efficiently as possible. For example, something like this:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Parent</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-keyword">const</span> data = { id: <span class="hljs-string">"123"</span> };
  <span class="hljs-keyword">const</span> onClick = <span class="hljs-function">() =&gt;</span> {

  };

  <span class="hljs-keyword">return</span> &lt;Component onClick={onClick} data={data} /&gt;
}
</code></pre>
<p>Will be transformed into this:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Parent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> $ = _c(<span class="hljs-number">1</span>);
  <span class="hljs-keyword">let</span> t0;
  <span class="hljs-keyword">if</span> ($[<span class="hljs-number">0</span>] === <span class="hljs-built_in">Symbol</span>.for(<span class="hljs-string">"react.memo_cache_sentinel"</span>)) {
    <span class="hljs-keyword">const</span> data = {
      id: <span class="hljs-string">"123"</span>,
    };
    <span class="hljs-keyword">const</span> onClick = _temp;
    t0 = &lt;Component onClick={onClick} data={data} /&gt;;
    $[<span class="hljs-number">0</span>] = t0;
  } <span class="hljs-keyword">else</span> {
    t0 = $[<span class="hljs-number">0</span>];
  }
  <span class="hljs-keyword">return</span> t0;
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_temp</span>(<span class="hljs-params"></span>) </span>{}
</code></pre>
<p>Notice how <code>onClick</code> is cached as a <code>_temp</code> variable, but <code>data</code> is just moved inside the <code>if</code> statement. You can play around with it some more in the <a target="_blank" href="https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEACgIYwKY4AUAlEcADqYtFFyFg5EAmZOMkQC8jInl7IiTEAEYATAGYZRAL4BuFmw5cehAMIAbPHADWIovREA+Rto1biRSjljEAPPogBbAA6EqPUwjE1NhYANjM1U+ATJw-kEYgHprFlUWEFUgA">Compiler Playground</a>.</p>
<p>The mechanics of how it works are fascinating, so if you want to know more, there are a few videos by the React core team available, such as the <a target="_blank" href="https://www.youtube.com/watch?v=0ckOUBiuxVY&amp;t=9309s&amp;ab_channel=ReactConf">Deep Dive into the Compiler talk</a>.</p>
<p>I am more interested in whether expectations from the compiler match the reality and whether it’s ready for use by the broader public, like me.</p>
<p>The main questions that immediately come to mind for almost everyone when they hear about “the Compiler will memorize everything“ are:</p>
<ul>
<li><p><strong>What about the initial load performance</strong>? One of the bug arguments against “memorizing everything by default“ has always been that it can negatively affect it since React has to do much more stuff in advance when everything is memorized.</p>
</li>
<li><p><strong>Will it have a positive performance impact at all</strong>? How much of a problem are re-renders really?</p>
</li>
<li><p><strong>Can it really catch all re-renders</strong>? JavaScript is notorious for being fluid and ambiguous. Is the Compiler smart enough to really catch everything? Is it true that we will never have to think about memorization and re-renders again?</p>
</li>
</ul>
<p>To answer those questions, check out <a target="_blank" href="https://adevnadia.medium.com/how-react-compiler-performs-on-real-code-5241110febc5">this useful article</a>.</p>
<h2 id="heading-react-server-components-enhanced-support-for-pre-rendering-components">React Server Components: Enhanced Support for Pre-Rendering Components</h2>
<p><a target="_blank" href="https://react.dev/reference/rsc/server-components">React Server Components</a>, introduced experimentally in React 18, are getting a boost in React 19. They allow components to run on the server during the initial render, fetching data and performing other server-side logic before sending HTML to the client. This leads to faster initial page loads, improved SEO, and a better overall user experience.</p>
<p>But let’s get something straight before we dive in:</p>
<p>RSC is not a new standard, engine, or framework.</p>
<p>It’s a low-level React API that enables you to render components entirely on the server, stream to the client, and hydrate only the parts that need interactivity.</p>
<p>Each framework (like Next.js, Remix, Hydrogen, etc.) builds its own opinionated implementation of RSC, deciding on key points.</p>
<ul>
<li><p>How server rendering is integrated</p>
</li>
<li><p>How data is fetched</p>
</li>
<li><p>How streaming works</p>
</li>
<li><p>How the server transfers data to the browser</p>
</li>
<li><p>How caching and revalidations are handled</p>
</li>
</ul>
<p>So, if you are using Next.js App Router, you are using RSC’s implementation specifically, not just “React Server Components“ in the abstract.</p>
<h3 id="heading-why-do-we-need-server-components">Why do we need Server Components?</h3>
<p>Server Components aim to solve long-standing web application pain points that were progressing over time, and the release of new tools, frameworks, and requirements:</p>
<ol>
<li><strong>Less JavaScript shipped to the client</strong></li>
</ol>
<p>Yes! The problem that we have heard for decades, and with each new tool, convinces us that the problem is finally solved. But the ideal is straightforward: render everything on the browser and pass it to the client.</p>
<ol start="2">
<li><strong>Direct server-side data access</strong></li>
</ol>
<p>There are still common issues and hot topics for lots of developers on “How should I fetch the data, and how does it affect my page rendering?“ We no longer need it, since components can talk directly to databases, file systems, or other APIs.</p>
<ol start="3">
<li><strong>Faster initial loads via streaming</strong></li>
</ol>
<p>No need to wait for full page rendering, especially when it contains some heavy parts; you can start sending your HTML chunk by chunk as soon as they are ready.</p>
<ol start="4">
<li><strong>Improved developer experience</strong></li>
</ol>
<p>You can write UI and data fetching altogether in a single place, without worrying about serialization and fetching life cycles.</p>
<p>Those old days when we just had an Express Server with Handlebars (or PHP or Rails), and rendering the whole template on the server and just sending it to the client. The difference? It’s just React — with streaming, selective hydration, and all the modern bells and whistles.</p>
<h3 id="heading-server-components-trade-offs">Server Components Trade-Offs</h3>
<p>As I already mentioned, you should keep an eye on the exact implementation of server components for a specific component, because implementations are unique; there is no standard, so whatever was working for you in one framework might work absolutely differently in another framework.</p>
<p>But besides that, we need to consider RSC changes <strong>where</strong> and <strong>how</strong> rendering happens:</p>
<ul>
<li><p>Every render of a Server Component happens on the server, not in the browser.</p>
</li>
<li><p>Browser no longer receives compiled JavaScript with your page bundle, which to render on the client - it receives a serialized “Flight” payload, which is telling it how to rebuild UI (rsc specific format).</p>
</li>
<li><p>Client Components still exist in bundle, but they form hydration islands inside the server-render tree.</p>
</li>
<li><p>Crossing a Server &lt;&gt; Client boundary is a serialization cost you pay every time.</p>
</li>
</ul>
<p>These differences bring <strong>new pitfalls</strong> that we need to consider, and in the meantime, it does not remove the rest of the pitfalls that we had for SSR apps, which we still need to consider as well.</p>
<h3 id="heading-the-real-performance-costs-of-server-components">The Real Performance Costs of Server Components</h3>
<ol>
<li><strong>Flight Payload Overhead (Server &lt;&gt; Client Boundaries)</strong></li>
</ol>
<p>In RSC, only Client Components hydrate — so any props passed from Server to Client must be serialized onto a <strong>Flight payload</strong>. Large or deeply nested props bloat the payload and delay hydration.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ❌ Large object crossing boundary → huge Flight payload</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ServerPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> bigData = <span class="hljs-keyword">await</span> getLargeDataset(); <span class="hljs-comment">// thousands of rows</span>
  <span class="hljs-keyword">return</span> &lt;ClientChart data={bigData} /&gt;; <span class="hljs-comment">// sent in Flight payload</span>
}

<span class="hljs-comment">// ✅ Send only what’s needed</span>
&lt;ClientChart data={summaryRows} /&gt;
</code></pre>
<p><strong>Mental picture:</strong></p>
<p>It’s like shipping an entire warehouse to the customer’s house when they only ordered a single chair — and having them unpack it before they can use anything.</p>
<p>2. <strong>Streaming Delays for long and heavy components. Suspense order matters!</strong></p>
<p>RSC supports streaming — sending UI chunks to the browser as they are ready. If a slow server component sits above others without a Suspense boundary, it blocks the whole stream until it finishes.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ❌ One slow server call holds up the entire page</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> slowFetch();
  <span class="hljs-keyword">return</span> &lt;MainContent data={data} /&gt;;
}

<span class="hljs-comment">// ✅ Wrap slow sections in Suspense</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      &lt;Header /&gt;
      &lt;Suspense fallback={&lt;Loading /&gt;}&gt;
        &lt;SlowSection /&gt;
      &lt;/Suspense&gt;
    &lt;/&gt;
  );
}
</code></pre>
<p><strong>Mental picture:</strong></p>
<p>Like waiting for the slowest dish at a restaurant before you’re allowed to eat anything.</p>
<p>3. <strong>Use client scope explosion</strong></p>
<p>Putting “use client” at the top of a big/shared file promotes that file (and often its imports) to a Client Component, erasing the “no JS for server code” benefit and inflating bundles. Which might be okay for some of the cases, but it still requires an additional learning curve for developers and understanding application specifics.</p>
<p>4. <strong>Community support</strong></p>
<p>RSC changes the rules - and many libraries still aren’t ready for it. Some require “use client” to function, which negates many of RSC’s benefits. Be prepared: your favorite library might not yet work well in a Server Component environment. For example, most CSS-in-JS frameworks (MUI, Chakra, Stitches, etc.) currently require “use client”.</p>
<h3 id="heading-how-react-server-components-work">How React Server Components Work</h3>
<p>RSCs are rendered on the server and send a special data format (called the React Server Component Payload) to the client. This payload describes the component tree and its properties. The client-side React runtime then uses this payload to hydrate the HTML and make the application interactive.</p>
<p>Here’s a simplified illustration:</p>
<ol>
<li><p>Request: The user requests a page</p>
</li>
<li><p>Server Rendering: The server renders the RSCs, fetching data and generating HTML, and the React Server Component Payload</p>
</li>
<li><p>Response: The server sends the HTML and the payload to the client.</p>
</li>
<li><p>Client Hydration: The client-side React runtime hydrates the HTML using the payload, making the application interactive.</p>
</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-comment">// Server Component (server-side)</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductDetails</span>(<span class="hljs-params">{ productId }</span>) </span>{
  <span class="hljs-string">'use server'</span>; <span class="hljs-comment">// Marks this as a Server Component</span>
  <span class="hljs-keyword">const</span> product = <span class="hljs-keyword">await</span> fetchProductData(productId); <span class="hljs-comment">// Fetch data on the server</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{product.name}<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>{product.description}<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>
  );
}

<span class="hljs-comment">// Client Component (client-side)</span>
<span class="hljs-string">'use client'</span>; <span class="hljs-comment">// Marks this as a Client Component</span>
<span class="hljs-keyword">import</span> ProductDetails <span class="hljs-keyword">from</span> <span class="hljs-string">'./ProductDetails'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductPage</span>(<span class="hljs-params">{ productId }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ProductDetails</span> <span class="hljs-attr">productId</span>=<span class="hljs-string">{productId}</span> /&gt;</span></span>;
}
</code></pre>
<p>In this example, the <code>ProductDetails</code> component is a Server Component that fetches product data on the server and renders the HTML. The <code>ProductPage</code> component is a Client Component that renders the <code>ProductDetails</code> component.</p>
<h3 id="heading-ssr-vs-react-server-components-key-differences">SSR vs. React Server Components: Key Differences</h3>
<p>Server-Side Rendering (SSR) is the classic approach: on each request, the server renders React components to HTML and sends it to the browser. The browser then downloads the JavaScript bundle and <strong>hydrates</strong> the static HTML to make it interactive. This drastically improves time-to-first-byte and SEO, since crawlers get the full markup immediately. The diagram below illustrates this flow:</p>
<p><strong>Figure</strong>: Traditional SSR flow. The client requests a page, the server renders full HTML (optionally fetching data), and returns it. The browser shows content quickly, then fetches the React bundle to hydrate and become interactive.</p>
<p>ReactDOM’s streaming APIs (e.g <code>renderToPipeableStream</code>) in React 18+, let the server send HTML in chunks. Wrapping parts of your app in <code>&lt;Suspense&gt;</code> boundaries can stream fallbacks first. For example, wrapping a slow <code>&lt;Posts /&gt;</code> component in <code>&lt;Suspense&gt;</code> sends the loading fallback immediately, then streams the post’s HTML later. This means the page displays content faster while waiting for data (React 18’s streaming SSR).</p>
<p>BY contrast, <strong>React Server Components (RSC)</strong> are a newer paradigm (made stable in React 19) that lets you mark the entire component to run only on the server. A Server Component can fetch data or use server-only APIs, but <strong>its code is never sent to the client</strong>.</p>
<p>Instead, Next.js (or another framework) will send a compact “RSC Payload” of HTML and instructions for client components. The browser first displays a fast HTML snapshot, and React hydrates only the client components for interactivity. The figure below shows this split rendering: the server first sends a page shell, then streams the remaining HTML and component payload to the client for hydration.</p>
<p>Figure: React Server lifecycle (Next.js App Router). The server renders a page shell and streams React Server Components payloads. The client shows initial HTML quickly, then uses the RSC payload to hydrate client-side components.</p>
<p>Key differences summarized:</p>
<ul>
<li><p><strong>Execution environment</strong>: SSR components (in frameworks) run on the server on every request (or at build time), then hydrate on the client. RSC runs on the server and never hydrates at all (no state, effects), reducing JS sent to the browser.</p>
</li>
<li><p><strong>Bundling</strong>: Traditional SSR still ships the full React app bundle for hydration. RSC lets you exclude code: only client components (marked with ‘use client‘) are bundled to the browser. This yields smaller client bundles and fewer JS dependencies.</p>
</li>
<li><p><strong>Data fetching</strong>: SSR can fetch data on the server (often via <code>getServerSideProps</code> or loaders). RSC can use <code>async/await</code> directly in component code (React 19+ supports <code>async</code> components), so you can <code>await</code> database/API calls within a Server Component.</p>
</li>
<li><p><strong>Interactivity</strong>: With SSR, hydration makes the entire UI interactive. With RSC, only designated client components hydrate. You “opt in” with <code>'use client'</code> directives for interactive parts, keeping the rest static.</p>
</li>
<li><p><strong>Relationship</strong>: RSC does not replace SSR — they complement it. In practice, you still do an initial SSR render, but many components can be RSC so less Js/state is shipped.</p>
</li>
</ul>
<p>In React 19+(end of 2024), RSC features are stable and can run *ahead of time (*e.g, at build time) or per request. That means you can use RSC for both static generation and dynamic SSR. The React 19 release notes explain that Server Components can be executed in a “separate environment” (your server) and target React 19 via the new <code>react-server</code> export condition.</p>
<p>There are some rules you can’t break, but overall, you are free to mix and match components.</p>
<p>The only limitations:</p>
<ul>
<li><p>Server-side components can’t be imported by client-side components. After all, the server-side one might have server-specific code that won’t work on the browser.</p>
</li>
<li><p>You can pass props between server and client components, but the data in them needs to be serializable. This is obvious if you think about it, after all, there is no easy way to transfer a class or a date object between server and client. And whether you realize it or not, that’s what you are doing by sharing props; you are transferring data between both environments.</p>
</li>
</ul>
<h3 id="heading-how-do-you-define-a-server-component-in-nextjs-13">How do you define a server component in Next.js 13?</h3>
<p>This is the best part; doing this is trivial.</p>
<p>To define a client component, simply add the <code>‘use client’</code> directive at the top of the file.</p>
<p>You only have to do that with the components you specifically want to be rendered on the client; otherwise, Next will decide where to render them based on the code you are using.</p>
<p>For example, if you don’t specify a directive, and inside your component, you use <code>useEffect</code> or <code>useState</code> Next, it will still render it inside the browser.</p>
<p>However, if you write it like this, the component will be rendered on the back end.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getActivity</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> result = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://www.boredapi.com/api/activity?type=recreational"</span>)
    <span class="hljs-keyword">const</span> obj = <span class="hljs-keyword">await</span> result.json()
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">activity</span>: obj.activity }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Bored</span> (<span class="hljs-params"></span>) </span>{

    <span class="hljs-keyword">let</span> activity = <span class="hljs-keyword">await</span> getActivity();

    <span class="hljs-keyword">return</span> (
       <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>
        Your activity
       <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>
        {activity.activity}
       <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>)
}
</code></pre>
<p>This code defines an async function that will render the component. It also performs a <code>async</code> fetch operation to get some data from an external API.</p>
<p>The rendered output from this component and the app using it is the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735208359666/d21e6650-11a6-472f-a718-7e686e5c9ca4.webp" alt class="image--center mx-auto" /></p>
<p>The screenshot shows the dev tools on Firefox. You can see there are no XHR requests for the site. That’s because this component was rendered on the server.</p>
<p>You can’t even get the source code for this component in the dev mode, because all we get on the browser is the result.</p>
<h2 id="heading-server-actions-streamlining-server-side-logic-in-react-19">Server Actions: Streamlining Server-Side Logic in React 19</h2>
<p>React 19 introduces <a target="_blank" href="https://react.dev/reference/rsc/server-actions">Server Actions</a>, a new feature that allows you to run server-side logic directly from your React components without needing to set up separate API endpoints. This approach simplifies server interactions, reduces the client-side JavaScript payload, and improves performance by executing heavy or secure operations on the server.</p>
<p>Server Actions are especially useful for handling operations like form submissions, database mutations, and other server-only logic directly within the React component tree. They seamlessly integrate server-side execution into the React application flow.</p>
<h3 id="heading-how-server-actions-work">How Server Actions Work</h3>
<p>Server Actions work by marking specific functions as server-side with a ‘<code>use server</code>’ directive. This lets React know that the code should run on the server, not the client, which keeps sensitive logic off the user’s device and improves security.</p>
<h3 id="heading-code-snippet-using-server-actions-in-react-19">Code Snippet: Using Server Actions in React 19</h3>
<p>Here’s an example demonstrating how to use Server Actions to handle a form submission without setting up separate API endpoints:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/SubmitForm.js</span>
<span class="hljs-string">'use server'</span>; <span class="hljs-comment">// This directive tells React that this function runs on the server</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">submitForm</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-comment">// Simulate a server-side operation, like saving to a database</span>
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Processing data on the server:'</span>, data);

  <span class="hljs-comment">// Example of server-side logic</span>
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/save'</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
    },
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(data),
  });

  <span class="hljs-keyword">if</span> (!response.ok) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Failed to save data on the server.'</span>);
  }

  <span class="hljs-keyword">return</span> response.json();
}
</code></pre>
<h3 id="heading-component-using-the-server-action">Component Using the Server Action</h3>
<pre><code class="lang-javascript"><span class="hljs-comment">// app/FormComponent.js</span>
<span class="hljs-string">'use client'</span>; <span class="hljs-comment">// This is a client component</span>

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { submitForm } <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/SubmitForm'</span>; <span class="hljs-comment">// Import the server action</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FormComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [formData, setFormData] = useState({ <span class="hljs-attr">name</span>: <span class="hljs-string">''</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">''</span> });
  <span class="hljs-keyword">const</span> [message, setMessage] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> submitForm(formData); <span class="hljs-comment">// Call the server action directly</span>
      setMessage(<span class="hljs-string">'Form submitted successfully!'</span>);
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server response:'</span>, result);
    } <span class="hljs-keyword">catch</span> (error) {
      setMessage(<span class="hljs-string">'Error submitting form.'</span>);
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error:'</span>, error);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{formData.name}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setFormData({ ...formData, name: e.target.value })}
        placeholder="Name"
      /&gt;
      <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">value</span>=<span class="hljs-string">{formData.email}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setFormData({ ...formData, email: e.target.value })}
        placeholder="Email"
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {message &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p>React 19 Server Actions provide a streamlined way to manage server-side logic directly within your React components. This reduces the need for separate API layers and enhances overall application performance. By leveraging this feature, developers can create more responsive, secure, and maintainable applications.</p>
<p><a target="_blank" href="https://javascript.plainenglish.io/react-v19-hooks-in-action-50e3a2b5face">https://javascript.plainenglish.io/react-v19-hooks-in-action-50e3a2b5face</a></p>
<h2 id="heading-reacts-cache">React’s <code>cache</code></h2>
<p>React 19 introduced a new feature that improves data fetching in server-side React apps. One of them is the cache function, a built-in mechanism for memorizing the results of function calls on the server. In simpler terms, the cache function allows to to avoid repeating expensive computations or data fetches when the same inputs occur during a single render cycle. It does this through memorization, storing the results of the function calls and reusing them if the same arguments are passed in the future.</p>
<p>This behavior saves resources and boosts speed.</p>
<p>The <code>cache</code> API is only available in React Server Components (RSC). In client-side React, you would use other techniques (like hooks <code>useMemo</code> and <code>useEffect</code>) for caching, but on the server, the <code>cache</code> function is the right tool.</p>
<h3 id="heading-the-problem-of-redundant-data-fetches">The problem of redundant data fetches</h3>
<p>In a framework such as Next.js 15, it’s common to break pages into components and even use parallel routes (multiple segments rendered concurrently). These components might need the same data. For example, two different parts of the page both require a user’s profile or a list of products.</p>
<p>Without caching, this often means making duplicate database (DB) or API calls. For instance, if two sibling components (or parallel route segments) each query the DB for the user’s info, you would normally end up hitting the DB twice for the same query. This slows your app, increases server loads, and potentially leads to inconsistent data if one request finishes before the other.</p>
<p>In the past, avoiding redundancy required workarounds like lifting data fetching up to a common parent and passing props down, or implementing a manual caching layer. However, lifting the state up makes your component less modular. Custom caching logic also gets messy. What we want is a way for each component to request the data it needs independently while automatically deduplicating identical requests during the render cycle. This is exactly the use case React’s cache function is designed to handle.</p>
<h3 id="heading-how-reacts-cache-works">How React’s cache works</h3>
<p>React’s cache function creates a memoized version of any asynchronous function. When you wrap a function with cache, React will store its results in memory the first time it’s called. Subsequent calls to the cached function with the same arguments will return cached results instantly, skipping the actual function execution. In other words, the first call is the cache miss (triggers the real fetch or computation), and later calls (with identical parameters) are cache hits that reuse the result.</p>
<p>This cache is scoped to a single server render cycle. During a server-side render, if multiple server components invoke the same cached function with the same arguments. React runs the underlying operations (e.g., the DB query) only once. It prevents redundant, expensive operations by reusing cached results. This avoids unnecessary network requests. This means fewer DB hits or API calls for that page render, leading to better performance and consistency. All components get the same result object, so they stay in sync.</p>
<p>Equally important, the cache is automatically cleared after the render is complete. React clears the cache after every server request. It invalidates all cached results at the end of each server request/render, so the next time you render that page (or another user requests it), React fetches fresh data.</p>
<p>There’s no need to worry about manual cache invalidation or stale data in subsequent requests. By design, each new request gets a new, empty cache. This makes the <code>cache</code> function a <strong>per-request memoization</strong>. Each call to <code>cache(fn)</code> returns a new memoized function with its own storage, and errors are cached the same way as successful results.</p>
<p>It differs from persistent caches (like data cached to disk or long-lived in-memory caches). Those would need explicit invalidation strategies, but this built-in cache is transient and lives only for the duration of the render. As the Next.js <a target="_blank" href="https://nextjs.org/docs/app/guides/caching">doc</a> notes, the cache (for memoized fetches or functions) <em>"lasts the lifetime of a server request until the React component tree has finished rendering"</em> and is not shared across requests.</p>
<p>In practice, this means each page load or navigation gets fresh data, which is ideal for most cases where you want real-time updated info on a new request.</p>
<h3 id="heading-using-reacts-cache-in-a-nextjs-app-supabase-example">Using React’s <code>cache</code> in a Next.js App (Supabase Example)</h3>
<p>Let’s walk through a concrete example to see the <code>cache</code> function in action. With a Next.js app using the App Router, you have two parallel route segments on a dashboard page, say, a user profile section and a sidebar with user stats. Both segments need to retrieve the user's profile data from the DB. We'll use Supabase as the DB client for this example (Supabase provides a JS client to query your DB directly from server code).</p>
<p>First, we can set up a Supabase client (for example, using the project URL and anon key in an environment config). Then we write a data-fetching function to get the user profile. We’ll wrap this function with the <code>cache</code> function:</p>
<blockquote>
<p><em>Next.js 15 defaults</em> <code>fetch</code> to <code>cache: 'no-store'</code>. Identical calls are still deduplicated in one render, but each new request fetches fresh data unless you opt in with <code>cache: 'force-cache'</code> or revalidation.</p>
</blockquote>
<pre><code class="lang-typescript"><span class="hljs-comment">// utils/dataFetcher.ts</span>
<span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/supabase-js'</span>;
<span class="hljs-keyword">import</span> { cache } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);

<span class="hljs-comment">// Define a cached function to fetch a user profile by ID</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getUserProfile = cache(<span class="hljs-keyword">async</span> (userId: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
    .from(<span class="hljs-string">'profiles'</span>)
    .select(<span class="hljs-string">'*'</span>)
    .eq(<span class="hljs-string">'id'</span>, userId)
    .single();

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;

  <span class="hljs-keyword">return</span> data;
});
</code></pre>
<p>In the code above, <code>getUserProfile</code> is a memoized function. The first time you call <code>getUserProfile('abc123')</code> for a given request, it will actually run the query against Supabase. If you call <code>getUserProfile('abc123')</code> again (anywhere else in the React tree during the same render), it will instantly return the cached result instead of querying the DB a second time. This pattern can be seen in real projects. For example, a Supabase utility might export cached queries like this to prevent duplicate calls.</p>
<p>Now, suppose our Next.js page uses parallel routes or multiple components that need this data:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/dashboard/@main/page.tsx</span>
<span class="hljs-keyword">import</span> { getUserProfile } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/utils/dataFetcher'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MainSection</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> getUserProfile(userId);
  <span class="hljs-keyword">return</span> &lt;ProfileDetails user={user} /&gt;;
}

<span class="hljs-comment">// app/dashboard/@sidebar/page.tsx</span>
<span class="hljs-keyword">import</span> { getUserProfile } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/utils/dataFetcher'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Sidebar</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> getUserProfile(userId);
  <span class="hljs-keyword">return</span> &lt;UserStats user={user} /&gt;;
}
</code></pre>
<p>In this simplified example, <code>MainSection</code> and <code>Sidebar</code> are two parallel segments (or could simply be two sibling server components) that both fetch the user’s profile. Thanks to React’s <code>cache</code>, the database is hit only once for <code>getUserProfile(userId)</code> during the server render. The first call (say, in <code>MainSection</code>) will query the DB (cache miss), and the second call (in <code>Sidebar</code>) will find the result already in cache (cache hit), avoiding another DB round-trip. Without the cache, we would have executed two identical queries to Supabase. With <code>cache</code>, React makes sure those components share the work and render the same snapshot of data.</p>
<p>It’s worth noting that this caching works for any kind of function, not just DB calls. You could use it to memoize expensive calculations or calls to other APIs or CMS systems. The key is that the function should be called within the React server render cycle (e.g., inside an <code>async</code> server component or during data fetching in a Next.js route).</p>
<p>If you try to call the cached function outside of rendering (for example, at the top level of your module when defining it or in a non-React context), it will still execute but won’t use React’s <code>cache</code>. React only provides cache access during the rendering of components. In practice, you usually call the cached function inside your server components as shown above, which is the correct usage.</p>
<h3 id="heading-benefits-of-using-reacts-cache">Benefits of Using React’s <code>cache</code></h3>
<ul>
<li><p><strong>Fewer DB/API calls:</strong> By deduplicating identical requests, you drastically cut down on redundant calls. The same function called multiple times with the same arguments will hit the server or DB only once. This reduces server workload and network traffic.</p>
</li>
<li><p><strong>Improved Performance:</strong> Reusing cached data results in faster response times and a smoother user experience. The page can render faster since subsequent components don’t have to wait for repeat fetches. In our example, the second component gets the data almost instantly from memory.</p>
</li>
<li><p><strong>Consistent Data:</strong> When multiple parts of the UI request the same info, using a single cached result means they all render with the same data. There’s no risk of one component showing stale data while another fetches fresh data moments later. During that render, they share the exact result.</p>
</li>
<li><p><strong>Simplified Code:</strong> React’s <code>cache</code> lets each component fetch what it needs without complex prop drilling or higher-level coordination. This keeps components more independent and readable, while the caching happens transparently under the hood. You don’t need ad hoc context providers or singletons to share data. Just call the cached function wherever needed.</p>
</li>
<li><p><strong>No Manual Invalidation Needed:</strong> Because the cache resets on every new request, you get fresh data on the next render by default. This ephemeral caching means you don’t have to write extra logic to invalidate or update the cache for new requests. (If you do want to cache across requests, you’d use other Next.js opt-in caching features, but that’s a different mechanism beyond our scope here.)</p>
</li>
</ul>
<h2 id="heading-async-transitions-simplifying-state-changes">Async Transitions: Simplifying State Changes</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752230394085/974ace2f-c29d-4eef-a84c-617315f83472.webp" alt class="image--center mx-auto" /></p>
<p>React 19 introduces Async Transitions, a powerful new feature designed to simplify the management of complex state updates that involve asynchronous operations, such as data fetching or animations. This feature builds upon the existing <code>useTransition</code> hook, providing a more elegant and efficient way to handle UI updates that depend on asynchronous results.</p>
<h3 id="heading-the-problem-with-traditional-state-transitions">The Problem with Traditional State Transitions</h3>
<p>Managing state updates that depend on asynchronous operations often requires complex logic and careful coordination of multiple state variables. This can lead to code that is difficult to read, maintain, and reason about.</p>
<p>Consider a scenario where you are fetching the data and updating the UI based on the result:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [isPending, setIsPending] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      setIsPending(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/data'</span>);
        <span class="hljs-keyword">const</span> json = <span class="hljs-keyword">await</span> response.json();
        setData(json);
      } <span class="hljs-keyword">catch</span> (err) {
        setError(err);
      } <span class="hljs-keyword">finally</span> {
        setIsPending(<span class="hljs-literal">false</span>);
      }
    };

    fetchData();
  }, []);

  <span class="hljs-keyword">if</span> (isPending) {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
  }

  <span class="hljs-keyword">if</span> (error) {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Error: {error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
  }

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Data: {JSON.stringify(data)}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<p>This code uses multiple state variables (<code>data</code>, <code>isPending</code>, <code>error</code>) to manage the asynchronous operation and its effects on the UI. This pattern can become even more complex when dealing with multiple asynchronous operations or more intricate UI updates.</p>
<h3 id="heading-simplifying-state-updates-with-async-transitions">Simplifying State Updates With Async Transitions</h3>
<p>Async Transitions simplifies this process by providing a way to perform asynchronous operations within a transition. This allows React to handle the pending state and prioritize user interactions during the asynchronous operation.</p>
<p>The <code>useTransition</code> hook now supports asynchronous functions as the update parameter. This allows you to directly perform asynchronous actions within a transition.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState, useTransition } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [isPending, startTransition] = useTransition();

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">() =&gt;</span> {
    startTransition(<span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/data'</span>);
        <span class="hljs-keyword">const</span> json = <span class="hljs-keyword">await</span> response.json();
        setData(json);
      } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-comment">// Handle error</span>
        <span class="hljs-built_in">console</span>.error(err)
      }
    });
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span> <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isPending}</span>&gt;</span>
        Fetch Data
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {isPending &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>}
      {data &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Data: {JSON.stringify(data)}<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>
  );
}
</code></pre>
<p>In this example, the asynchronous data fetching is wrapped within <code>startTransition</code>. React automatically manages the <code>isPending</code> state during the fetch. This results in cleaner code and a more streamlined approach to managing asynchronous state updates.</p>
<h3 id="heading-key-benefits-of-async-transitions">Key Benefits of Async Transitions</h3>
<ul>
<li><p><strong>Simplified State Management</strong>: Reduces the need for multiple state variables to manage asynchronous operations.</p>
</li>
<li><p><strong>Improved User Experience</strong>: Ensures that user interactions are prioritized during asynchronous operations, preventing the UI from becoming unresponsive.</p>
</li>
<li><p><strong>Cleaner Code</strong>: Makes code that deals with asynchronous state updates more concise and easier to read.</p>
</li>
<li><p><strong>Built-in Pending State Handling</strong>: React automatically manages the pending state, reducing the boilerplate code.</p>
</li>
<li><p><strong>Integration with Suspense</strong>: Async Transitions work well with Suspense for more declarative loading states.</p>
</li>
</ul>
<p>Async Transitions provide a powerful and elegant way to manage complex state changes involving asynchronous operations. By simplifying state management and improving user experience, Async Transitions contribute to building more performant and maintainable React applications.</p>
<h2 id="heading-useotimistic-managing-optimistic-updates-with-ease"><code>useOtimistic</code>: Managing optimistic updates with ease</h2>
<p>React 19 introduces the <code>useOtimistic</code> hook, a powerful tool for simplifying the implementations of optimistic updates. Optimistic updates drastically improve user experience by providing the illusion of instant UI changes, even before the corresponding server-side operations are confirmed. This creates a more responsive and fluid interaction.</p>
<h3 id="heading-the-problem-with-traditional-optimistic-updates">The Problem with Traditional Optimistic Updates</h3>
<p>Traditionally, implementing optimistic updates in React involved manual state management. This often led to several challenges:</p>
<ul>
<li><p><strong>Complex State Logic</strong>: Developers had to manually manage the optimistic state alongside the actual data, often requiring intricate logic to update and revert changes. This could lead to complex and hard-to-maintain code.</p>
</li>
<li><p><strong>Potential for Inconsistencies</strong>: Manually managing states increases the risk of inconsistencies between the UI and the actual data. For instance, forgetting to revert an optimistic update after a failed server request could lead to a desynchronized user interface.</p>
</li>
<li><p><strong>Boilerplate code</strong>: Implementing optimistic updates often requires a significant amount of boilerplate code to handle state updates, error handling, or reverting changes. This increases development time and makes the code less readable.</p>
</li>
<li><p><strong>Difficulty in Handling Complex Updates</strong>: When dealing with more complex data structures or multiple concurrent updates, manually managing the optimistic state becomes even more challenging, increasing the likelihood of bugs.</p>
</li>
</ul>
<p>Consider a simple example of adding a new item to a list. Without <code>useOptimistic</code>, you might have code that looks something like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ItemList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [items, setItems] = useState([]);
  <span class="hljs-keyword">const</span> [isAdding, setIsAdding] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> addItem = <span class="hljs-keyword">async</span> (newItem) =&gt; {
    setIsAdding(<span class="hljs-literal">true</span>); <span class="hljs-comment">// Indicate loading state</span>
    setItems([...items, { ...newItem, <span class="hljs-attr">tempId</span>: <span class="hljs-built_in">Date</span>.now() }]); <span class="hljs-comment">// Optimistic update</span>

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/items'</span>, { <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>, <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(newItem) });
      <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
      setItems(items.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.tempId === newItem.tempId ? data : item)); <span class="hljs-comment">// Replace temp item</span>
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-comment">// Handle error and revert</span>
      setItems(items.filter(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.tempId !== newItem.tempId));
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error adding item:"</span>, error);
    } <span class="hljs-keyword">finally</span> {
      setIsAdding(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>This code, even in simplified form, demonstrates the complexity involved in manually managing optimistic updates.</p>
<h3 id="heading-simplifying-optimistic-updates-with-useoptimistic">Simplifying Optimistic Updates With <code>useOptimistic</code></h3>
<p><code>useOptimistic</code> addresses these issues by providing a declarative and streamlined way to manage optimistic updates. It simplifies the process by abstracting away the complexities of manual state management.</p>
<p>The <code>useOptimistic</code> hook takes 2 arguments:</p>
<ol>
<li><p>initialValue: The initial value of the state</p>
</li>
<li><p><code>updateFn</code>: The function that receives the current optimistic value and the update argument and returns the new optimistic value.</p>
</li>
</ol>
<p>It returns an array containing:</p>
<ol>
<li><p>optimisticValue: The current optimistic value</p>
</li>
<li><p><code>addOptimistic</code>: A function to apply an optimistic update</p>
</li>
</ol>
<p>Using the same “add item“ example, we can rewrite it using <code>useOptimistic</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ItemList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [items, setItems] = useState([]);
  <span class="hljs-keyword">const</span> [optimisticItems, addOptimisticItem] = useOptimistic(items, <span class="hljs-function">(<span class="hljs-params">prevItems, newItem</span>) =&gt;</span> [...prevItems, { ...newItem, <span class="hljs-attr">isOptimistic</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">id</span>: <span class="hljs-string">`temp-<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>`</span> }]);

  <span class="hljs-keyword">const</span> addItem = <span class="hljs-keyword">async</span> (newItem) =&gt; {
    addOptimisticItem(newItem);

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/items'</span>, { <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>, <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(newItem) });
      <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
        setItems(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> prev.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.id.startsWith(<span class="hljs-string">"temp-"</span>) ? data : item))
    } <span class="hljs-keyword">catch</span> (error) {
        setItems(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> prev.filter(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> !item.id.startsWith(<span class="hljs-string">"temp-"</span>)))
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error adding item:"</span>, error);
    }
  };

  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>This version is significantly cleaner and easier to understand, <code>useOptimistic</code> and handles the optimistic update logic, making the code more concise and less prone to errors. Key improvements include:</p>
<ul>
<li><p><strong>Simplified Logic</strong>: <code>useOptimistic</code> abstracts away the complexities of managing an optimistic state.</p>
</li>
<li><p><strong>Declarative Approach</strong>: The <code>updateFn</code> clearly defines how the optimistic state should be updated.</p>
</li>
<li><p><strong>Reduced Boilerplate</strong>: Less code is required to achieve the same functionality.</p>
</li>
</ul>
<p>By using <code>useOptimistic</code>, developers can focus on the core logic of their applications rather than getting bogged down in manual state management, leading to more maintainable and robust code.</p>
<h2 id="heading-useactionstate-simplifying-action-state-management"><code>useActionState</code>: Simplifying Action State Management</h2>
<p>React 19 introduces <code>useActionState</code>, a new hook designed to simplify the management of state related to asynchronous actions, such as form submissions or API calls. This hook streamlines the process of tracking loading states, errors, and the results of these actions, leading to cleaner and more maintainable code.</p>
<h3 id="heading-the-problem-with-traditional-action-state-management">The Problem With Traditional Action State Management</h3>
<p>Managing the state of asynchronous actions manually often leads to verbose and repetitive code. Common patterns involve using multiple state variables to track different aspects of the action:</p>
<ul>
<li><p><strong>Loading State</strong>: A boolean variable to indicate whether the action is in progress.</p>
</li>
<li><p><strong>Error State</strong>: A variable to store any errors that occur during the action.</p>
</li>
<li><p><strong>Result State</strong>: A variable to store the result of the action (e.g, the data returned from an API call)</p>
</li>
</ul>
<p>Consider a typical example of submitting a form:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [formData, setFormData] = useState({ <span class="hljs-attr">name</span>: <span class="hljs-string">''</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">''</span> });
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [result, setResult] = useState(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    setIsLoading(<span class="hljs-literal">true</span>);
    setError(<span class="hljs-literal">null</span>);

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/submit'</span>, {
        <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
        <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(formData),
      });
      <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
      setResult(data);
    } <span class="hljs-keyword">catch</span> (err) {
      setError(err);
    } <span class="hljs-keyword">finally</span> {
      setIsLoading(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>This code snippet, even in its simplified form, demonstrates the boilerplate involved in manually managing the action state. Each action requires managing multiple state variables and updating them within the action handler, which becomes increasingly cumbersome as the application's complexity grows.</p>
<h3 id="heading-simplifying-action-state-management-with-useactionstate">Simplifying Action State Management with useActionState</h3>
<p><code>useActionState</code> simplifies this process by encapsulating the state management logic within a single hook. It takes an asynchronous function (the action) as an argument and returns an array containing:</p>
<ol>
<li><p><strong>action</strong>: A function that triggers the asynchronous action</p>
</li>
<li><p><strong>state</strong>: An object containing the action’s state:</p>
<p> pending: A boolean indication of whether the action is in progress</p>
<p> error: Any error that occurred during the action<br /> data: The result of the action</p>
</li>
</ol>
<p>Using <code>useActionState</code>, the previous form example can be written as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useActionState, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [formData, setFormData] = useState({ <span class="hljs-attr">name</span>: <span class="hljs-string">''</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">''</span> });
  <span class="hljs-keyword">const</span> [submit, submitState] = useActionState(<span class="hljs-keyword">async</span> (data) =&gt; {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/submit'</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(data),
    });
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> response.json();
  });

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();
    submit(formData);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        {submitState.pending &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Submitting...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
        {submitState.error &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{color:</span> "<span class="hljs-attr">red</span>"}}&gt;</span>{submitState.error.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
        {submitState.data &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Success: {JSON.stringify(submitState.data)}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{formData.name}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setFormData({...formData, name: e.target.value})} /&gt;
            <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">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{formData.email}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{e</span> =&gt;</span> setFormData({...formData, email: e.target.value})} /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">disabled</span>=<span class="hljs-string">{submitState.pending}</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>This version is significantly cleaner and more concise, <code>useActionState</code> handles the state management behind the scenes, reducing boilerplate and improving code readability. Key improvements include:</p>
<ul>
<li><p><strong>Encapsulated State</strong>: All action-related state is managed within a single hook, making the component logic cleaner.</p>
</li>
<li><p><strong>Reduced Boilerplate</strong>: Significantly less code is required to manage loading states, errors, and results.</p>
</li>
<li><p><strong>Improved Readability</strong>: The code is easier to understand and maintain due to the simplified structure.</p>
</li>
</ul>
<p>By using <code>useActionState</code>, developers can streamline the management of asynchronous actions, resulting in more maintainable and efficient React applications. It promotes cleaner code by abstracting away the repetitive logic of manual state management for actions.</p>
<h2 id="heading-react-dom-useformstatus-simplifying-form-state-management-with-actions">React DOM: useFormStatus — Simplifying Form State Management With Actions</h2>
<p>React 19 introduces <code>useFormStatus</code>, a new hook specifically designed to simplify form-state management when used in conjunction with React Server Components and Actions. This hook provides valuable information about the status of a form submission, making it easier to provide feedback to the user and manage the form’s state.</p>
<h3 id="heading-the-problem-with-traditional-form-state-management-with-actions">The problem with traditional form state management with actions</h3>
<p>Traditionally, managing form submissions with server actions, especially in the context of React Server Components, required manual tracking of loading states and potential errors within the action itself. This could lead to scattered logic and make it difficult to provide a cohesive user experience.</p>
<p>Consider a typical form submission using a server action:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Server Action (server-side)</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">submitForm</span>(<span class="hljs-params">formData</span>) </span>{
  <span class="hljs-string">'use server'</span>;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Perform server-side logic (e.g., database update)</span>
    <span class="hljs-keyword">await</span> someDatabaseOperation(formData);
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> };
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">success</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">error</span>: error.message };
  }
}

<span class="hljs-comment">// Client Component (client-side)</span>
<span class="hljs-string">'use client'</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyForm</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [message, setMessage] = useState(<span class="hljs-literal">null</span>)
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleSubmit</span>(<span class="hljs-params">formData</span>) </span>{
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> submitForm(formData);
    <span class="hljs-keyword">if</span> (result.success) {
        setMessage(<span class="hljs-string">"Success!"</span>)
    } <span class="hljs-keyword">else</span> {
        setMessage(result.error)
    }
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
      {/* Form inputs */}
        {message &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p>With this approach, it lacks direct integration with the form’s submission process. There is no built-in way to easily access the pending state of the submission directly within the client component.</p>
<h3 id="heading-simplifying-form-state-management-with-useformstatus">Simplifying Form State Management With useFormStatus</h3>
<p>useFormStatus addresses this limitation by providing direct access to the form’s submission status. It’s designed to be used in the client component that renders a form element associated with a server action. The hook returns an object containing the following properties:</p>
<ul>
<li><strong>pending</strong>: A boolean indicating whether the form is currently being submitted.</li>
</ul>
<p>Using <code>useFormStatus</code>, the previous form example can be significantly improved:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Server Action (server-side)</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">submitForm</span>(<span class="hljs-params">formData</span>) </span>{
  <span class="hljs-string">'use server'</span>;
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Perform server-side logic</span>
    <span class="hljs-keyword">await</span> someDatabaseOperation(formData);
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> };
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">success</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">error</span>: error.message };
  }
}

<span class="hljs-comment">// Client Component (client-side)</span>
<span class="hljs-string">'use client'</span>;
<span class="hljs-keyword">import</span> { useFormStatus } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { pending } = useFormStatus();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">{submitForm}</span>&gt;</span>
      {/* Form inputs */}
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">disabled</span>=<span class="hljs-string">{pending}</span>&gt;</span>
        {pending ? 'Submitting...' : 'Submit'}
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p>This version is much cleaner and more directly integrated with the form’s submission process. Key improvements include:</p>
<ul>
<li><p><strong>Direct Access To Submission Status</strong>: <code>useFormStatus</code> provides a simple way to check if the form is pending submission.</p>
</li>
<li><p><strong>Improved User Experience</strong>: The pending state can provide immediate feedback to the user, such as disabling the submit button or displaying a loading indicator.</p>
</li>
<li><p><strong>Simplified Logic</strong>: No need for manual state management within the client component to track the submission status.</p>
</li>
</ul>
<p><code>useFormStatus</code> streamlines form handling with server actions, especially in React Server Components, leading to better user experiences and cleaner code. It also simplifies providing feedback during form submissions by directly exposing the submission state.</p>
<h2 id="heading-use-a-new-api-for-reading-resources-in-render"><code>use</code>: A New API for Reading Resources in Render</h2>
<p>React 19 shipped a new API called <code>use()</code>. It lets you <strong>read Promises and Context values during render</strong>, and it <strong>integrates with Suspense and Error Boundaries</strong>. Unlike Hooks, <code>use()</code> <strong>can be called in conditionals and loops</strong>, which unlocks simpler patterns you couldn’t express cleanly before. Let’s dive into how it works and see it in action.</p>
<h3 id="heading-what-use-actually-does"><strong>What</strong> <code>use()</code> actually does</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { use } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// Read a Promise (component suspends while pending)</span>
<span class="hljs-keyword">const</span> data = use(fetchSomething());

<span class="hljs-comment">// Read a Context (like useContext, but allowed in conditionals/loops)</span>
<span class="hljs-keyword">const</span> theme = use(ThemeContext);
</code></pre>
<ul>
<li><p>If you pass a <strong>Promise</strong>, React will <strong>suspend</strong> the component until it resolves. Pair it with a nearby <code>&lt;Suspense&gt;</code> for a good fallback. If it <strong>rejects</strong>, your <strong>nearest Error Boundary</strong> renders.</p>
</li>
<li><p>If you pass a <strong>Context</strong>, it behaves like <code>useContext</code>, <strong>but</strong> you can call it inside conditionals or loops. <code>use()</code> is <strong>preferred over</strong> <code>useContext</code> because it’s more flexible.</p>
</li>
</ul>
<blockquote>
<p><a target="_blank" href="https://react.dev/blog/2024/12/05/react-19"><em>React 19 announcement confirms</em> <code>use()</code> as a new API to “read resources in render.”</a></p>
</blockquote>
<h3 id="heading-why-use-exists-and-when-it-shines"><strong>Why</strong> <code>use()</code> exists (and when it shines)</h3>
<p>Historically, async reads in components were pushed into <strong>effects</strong> or third‑party caches, and Context reads had to be <strong>top‑level only</strong>. <code>use()</code> changes the ergonomics:</p>
<ul>
<li><p><strong>Conditional reads</strong>: Fetch or read Context <strong>only when needed</strong>, without refactoring into extra components.</p>
</li>
<li><p><strong>First‑class Suspense</strong>: Reading a Promise via <code>use()</code> naturally suspends and plays nicely with a <code>fallback</code>.</p>
</li>
<li><p><strong>Less boilerplate</strong>: No “loading”/“error” <code>useState</code> juggling just to read data on render—Suspense + Error Boundary handles it.</p>
</li>
</ul>
<h3 id="heading-why-use-is-more-flexible-than-usecontext"><strong>Why</strong> <code>use()</code> is more flexible than useContext</h3>
<p><strong>1) Call only when you actually need it (conditional reads)</strong></p>
<p>With <code>useContext</code>, you must call at the top level—even if you may not need the value on a given render. With <code>use()</code>, you can put the read behind a branch so it only happens when you render the thing that needs it.</p>
<p><strong>Before (</strong><code>useContext</code><strong>, always subscribes):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Menu</span>(<span class="hljs-params">{ open }: { open: <span class="hljs-built_in">boolean</span> }</span>) </span>{
  <span class="hljs-keyword">const</span> theme = useContext(ThemeContext); <span class="hljs-comment">// called every render</span>
  <span class="hljs-keyword">if</span> (!open) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  <span class="hljs-keyword">return</span> &lt;Panel className={theme} /&gt;;
}
</code></pre>
<p><strong>After (</strong><code>use</code><strong>, lazy subscription):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { use } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Menu</span>(<span class="hljs-params">{ open }: { open: <span class="hljs-built_in">boolean</span> }</span>) </span>{
  <span class="hljs-keyword">if</span> (!open) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;                <span class="hljs-comment">// no context read on closed state</span>
  <span class="hljs-keyword">const</span> theme = use(ThemeContext);       <span class="hljs-comment">// read only when open</span>
  <span class="hljs-keyword">return</span> &lt;Panel className={theme} /&gt;;
}
</code></pre>
<p><strong>2) Choose one of the many contexts without extra wrapper components</strong></p>
<p>With <code>useContext</code>, you can’t place the call in a branch; your fallback is to call <em>both</em> contexts at the top and pick one—subscribing to both. With <code>use()</code>, you just read the one you need.</p>
<p><strong>Before (</strong><code>useContext</code><strong>, forced multiple subscriptions or wrappers):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{ isAdmin }: { isAdmin: <span class="hljs-built_in">boolean</span> }</span>) </span>{
  <span class="hljs-keyword">const</span> admin = useContext(AdminThemeContext); <span class="hljs-comment">// subscribed even if !isAdmin</span>
  <span class="hljs-keyword">const</span> user  = useContext(UserThemeContext);  <span class="hljs-comment">// subscribed even if isAdmin</span>
  <span class="hljs-keyword">const</span> theme = isAdmin ? admin : user;
  <span class="hljs-keyword">return</span> &lt;button className={theme.btn} /&gt;;
}
</code></pre>
<p><strong>After (</strong><code>use</code><strong>, branch safely):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { use } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{ isAdmin }: { isAdmin: <span class="hljs-built_in">boolean</span> }</span>) </span>{
  <span class="hljs-keyword">const</span> theme = isAdmin ? use(AdminThemeContext) : use(UserThemeContext);
  <span class="hljs-keyword">return</span> &lt;button className={theme.btn} /&gt;;
}
</code></pre>
<p><strong>3) Read inside loops (plugin/slot UIs, data-driven rendering)</strong></p>
<p>When you render lists with per-item providers (slot/portal/plugin UIs), <code>use()</code> lets you read the right context <strong>inside the map</strong> without extracting a child component just to satisfy hook rules.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { use } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Toolbar</span>(<span class="hljs-params">{ items }: { items: <span class="hljs-built_in">Array</span>&lt;{ key: <span class="hljs-built_in">string</span> }&gt; }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;ul&gt;
      {items.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> (
        &lt;ItemProvider key={item.key} item={item}&gt;
          {<span class="hljs-comment">/* providers vary per item */</span>}
          &lt;li className={use(ItemThemeContext).li}&gt;
            {use(ItemLabelContext)}
          &lt;/li&gt;
        &lt;/ItemProvider&gt;
      ))}
    &lt;/ul&gt;
  );
}
</code></pre>
<p>Because <code>use()</code> is allowed in loops, this reads the provider that’s closest <strong>for that list item</strong>.</p>
<p><strong>4) Cleaner control-flow (no “wrapper components” to appease rules)</strong></p>
<p>With <code>useContext</code>, complex flows often force you to split components purely to keep the call at top level. <code>use()</code> lets you keep logic local:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">CTA</span>(<span class="hljs-params">{ mode }: { mode: "primary" | "secondary" | "link" }</span>) </span>{
  <span class="hljs-keyword">switch</span> (mode) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">"primary"</span>: {
      <span class="hljs-keyword">const</span> t = use(PrimaryTheme);
      <span class="hljs-keyword">return</span> &lt;button className={t.btnPrimary}&gt;Buy&lt;/button&gt;;
    }
    <span class="hljs-keyword">case</span> <span class="hljs-string">"secondary"</span>: {
      <span class="hljs-keyword">const</span> t = use(SecondaryTheme);
      <span class="hljs-keyword">return</span> &lt;button className={t.btnSecondary}&gt;Try&lt;/button&gt;;
    }
    <span class="hljs-keyword">default</span>: {
      <span class="hljs-keyword">const</span> t = use(LinkTheme);
      <span class="hljs-keyword">return</span> &lt;a className={t.link}&gt;Learn more&lt;/a&gt;;
    }
  }
}
</code></pre>
<p>This keeps related code together without creating three tiny components just to call a hook at the top.</p>
<p><strong>5) Works the same way for Promises (one mental model)</strong></p>
<p>The same <strong>“read where you need it”</strong> idea applies to Promises: <code>use(promise)</code> integrates with Suspense (pending → fallback) and Error Boundaries (rejected → error UI). So the same control-flow flexibility you get for context also applies to async reads.</p>
<p><strong>When to stick with</strong> <code>useContext</code></p>
<p>You don’t have to rewrite stable code. If a component always needs a context value unconditionally, <code>useContext</code> is perfectly fine. Reach for <code>use()</code> when:</p>
<ul>
<li><p>You only need the value in certain branches,</p>
</li>
<li><p>You want to avoid subscribing to multiple contexts just to pick one,</p>
</li>
<li><p>Or you want to keep loop/branch logic in the same component without wrapper components.</p>
</li>
</ul>
<h3 id="heading-the-rules-how-use-differs-from-hooks"><strong>The rules — how</strong> <code>use()</code> differs from Hooks</h3>
<p>We touched on some of these above — here’s the full set of rules at a glance.</p>
<ul>
<li><p><strong>Allowed in</strong> <code>if</code> <strong>and loops.</strong> This is the headline difference vs Hooks.</p>
</li>
<li><p>Must be called from a <strong>Component or a Hook</strong> (not from arbitrary functions or event handlers).</p>
</li>
<li><p><strong>Don’t call in</strong> <code>try/catch</code><strong>.</strong> Use an Error Boundary or <code>.catch</code> on the Promise to provide an alternate value.</p>
</li>
</ul>
<p><strong>Example 1 — Conditional Context (no extra wrapper components)</strong></p>
<p><strong>Before (</strong><code>useContext</code><strong>) – not allowed inside conditionals:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HorizontalRule</span>(<span class="hljs-params">{ show }: { show: <span class="hljs-built_in">boolean</span> }</span>) </span>{
  <span class="hljs-keyword">if</span> (show) {
    <span class="hljs-comment">// ❌ Illegal with useContext: cannot call inside conditionals</span>
    <span class="hljs-keyword">const</span> theme = useContext(ThemeContext);
    <span class="hljs-keyword">return</span> &lt;hr className={theme} /&gt;;
  }
  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}
</code></pre>
<p><strong>After (</strong><code>use</code><strong>) – legal and simple:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { use } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HorizontalRule</span>(<span class="hljs-params">{ show }: { show: <span class="hljs-built_in">boolean</span> }</span>) </span>{
  <span class="hljs-keyword">if</span> (!show) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  <span class="hljs-keyword">const</span> theme = use(ThemeContext); <span class="hljs-comment">// ✅ allowed in conditionals</span>
  <span class="hljs-keyword">return</span> &lt;hr className={theme} /&gt;;
}
</code></pre>
<p><strong>Example 2 — Streaming data (Server → Client) with Suspense +</strong> <code>use()</code></p>
<p>Create a Promise in a <strong>Server Component</strong> and pass it down:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// App.server.tsx</span>
<span class="hljs-keyword">import</span> { Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Message } <span class="hljs-keyword">from</span> <span class="hljs-string">'./Message.client'</span>;
<span class="hljs-keyword">import</span> { fetchMessage } <span class="hljs-keyword">from</span> <span class="hljs-string">'./lib'</span>; <span class="hljs-comment">// returns Promise&lt;string&gt;</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> messagePromise = fetchMessage(); <span class="hljs-comment">// created on the server</span>
  <span class="hljs-keyword">return</span> (
    &lt;Suspense fallback={&lt;p&gt;Downloading message…&lt;/p&gt;}&gt;
      &lt;Message messagePromise={messagePromise} /&gt;
    &lt;/Suspense&gt;
  );
}
</code></pre>
<p>Read it in a <strong>Client Component</strong> via <code>use()</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Message.client.tsx</span>
<span class="hljs-string">'use client'</span>;
<span class="hljs-keyword">import</span> { use } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Message</span>(<span class="hljs-params">{ messagePromise }: { messagePromise: <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt; }</span>) </span>{
  <span class="hljs-keyword">const</span> message = use(messagePromise); <span class="hljs-comment">// suspends while pending</span>
  <span class="hljs-keyword">return</span> &lt;p&gt;Message: {message}&lt;/p&gt;;
}
</code></pre>
<blockquote>
<p><em>Prefer creating Promises in</em> <a target="_blank" href="https://react.dev/reference/rsc/server-components"><em>Server Components</em></a> <em>and passing them to</em> <a target="_blank" href="https://react.dev/reference/rsc/use-client"><em>Client Components</em></a> <em>over creating Promises in Client Components. Promises created in Client Components are recreated on every render. Promises passed from a Server Component to a Client Component are stable across re-renders</em><a target="_blank" href="https://react.dev/reference/react/use#use"><em>. The docs spell out this stability difference.</em></a></p>
</blockquote>
<p><strong>Example 3 — Handling rejections: Error Boundary vs</strong> <code>.catch</code></p>
<p><strong>Don’t wrap</strong> <code>use()</code> <strong>in</strong> <code>try/catch</code><strong>.</strong> Use an Error Boundary or <code>.catch</code> on the Promise.</p>
<p><strong>With an Error Boundary:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { ErrorBoundary } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-error-boundary'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Container</span>(<span class="hljs-params">{ promise }: { promise: <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt; }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;ErrorBoundary fallback={&lt;p&gt;⚠️ Something went wrong.&lt;/p&gt;}&gt;
      &lt;Suspense fallback={&lt;p&gt;Loading…&lt;/p&gt;}&gt;
        &lt;Message messagePromise={promise} /&gt;
      &lt;/Suspense&gt;
    &lt;/ErrorBoundary&gt;
  );
}
</code></pre>
<p><strong>Or provide an alternate value with</strong> <code>.catch</code><strong>:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> safePromise = getMessage().catch(<span class="hljs-function">() =&gt;</span> <span class="hljs-string">'No new messages.'</span>);
<span class="hljs-comment">// use(safePromise) now resolves to a fallback string even if it rejectsconst safePromise = getMessage().catch(() =&gt; 'No new messages.');</span>
<span class="hljs-comment">// use(safePromise) now resolves to a fallback string even if it rejects</span>
</code></pre>
<p><strong>Example 4 — Loops: read multiple contexts or resources</strong></p>
<p>This is precisely what’s <em>not</em> allowed with Hooks — but it is with <code>use()</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { use } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ThemedList</span>(<span class="hljs-params">{ items }: { items: <span class="hljs-built_in">string</span>[] }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;ul&gt;
      {items.map(<span class="hljs-function">(<span class="hljs-params">label, i</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> theme = use(ThemeContext); <span class="hljs-comment">// ✅ inside a loop</span>
        <span class="hljs-keyword">return</span> &lt;li key={i} className={theme}&gt;{label}&lt;/li&gt;;
      })}
    &lt;/ul&gt;
  );
}
</code></pre>
<p><strong>What not to do</strong></p>
<p><strong>Don’t call</strong> <code>use()</code> <strong>in event handlers or arbitrary functions.</strong> Keep it in components/hooks.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Bad</span>(<span class="hljs-params">{ promise }: { promise: <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt; }</span>) </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onClick</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> data = use(promise); <span class="hljs-comment">// ❌ not a component or a hook</span>
    <span class="hljs-built_in">console</span>.log(data);
  }
  <span class="hljs-keyword">return</span> &lt;button onClick={onClick}&gt;Click&lt;/button&gt;;
}
</code></pre>
<h3 id="heading-use-vs-usecontext-vs-useeffect"><code>use()</code> vs <code>useContext</code> vs <code>useEffect</code></h3>
<p><code>use()</code> <strong>vs</strong> <code>useContext</code> <strong>(Context consumption)</strong></p>
<ul>
<li><p>Both return the nearest provider’s value.</p>
</li>
<li><p><code>useContext</code> must be <strong>top‑level</strong>; <code>use()</code> can be <strong>conditional/looped</strong> and is <strong>preferred</strong> going forward (no need to rewrite working code just for this).</p>
</li>
</ul>
<p><code>use()</code> <strong>vs</strong> <code>useEffect</code> <strong>(data fetching)</strong></p>
<ul>
<li><p><code>useEffect</code> runs <strong>after</strong> render; you juggle loading/error state and avoid race conditions manually.</p>
</li>
<li><p><code>use()</code> reads <strong>during</strong> render, and Suspense/Error Boundary handle pending/rejected states—much less boilerplate.</p>
</li>
<li><p>Still use <code>useEffect</code> for <strong>imperative</strong> work: subscriptions, DOM APIs, logging, non‑render‑blocking work.</p>
</li>
</ul>
<p><code>use()</code> <strong>vs data‑fetching libraries (React Query, SWR, Apollo, etc.)</strong></p>
<ul>
<li><p>Those libraries still shine for <strong>cache management, invalidation policies, retries, pagination, mutations</strong>.</p>
</li>
<li><p><code>use()</code> is a low‑level read mechanism integrated with Suspense. Combine them if your lib supports Suspense (many do).</p>
</li>
</ul>
<h3 id="heading-migration-strategy">Migration strategy</h3>
<ul>
<li><p><strong>New code:</strong> Prefer <code>use(YourContext)</code> over <code>useContext(YourContext)</code> for flexibility.</p>
</li>
<li><p><strong>Existing code:</strong> Don’t mass‑rewrite. If it’s stable, keep it. Incrementally migrate where conditionals/loops would simplify the structure. (The React docs say <code>use()</code> is preferred, but that doesn’t imply forced rewrites.)</p>
</li>
<li><p><strong>Async reads:</strong> In Server Components, prefer <code>await</code>; in Client Components, prefer passing a <strong>server‑created</strong> Promise down and reading via <code>use()</code> within Suspense.</p>
</li>
</ul>
<p><strong>Promise identity matters.</strong> Recreating a Promise on every render can cause repeated suspends. Prefer:</p>
<ol>
<li><p>Create Promises in <strong>Server Components</strong> and pass them to clients; or</p>
</li>
<li><p>Use a <strong>Suspense‑aware cache</strong> in your framework/library so the same work is reused across renders. The React 19 release notes call out the importance of caching for Promises read during render.</p>
</li>
</ol>
<h2 id="heading-ref-as-a-prop-simplifying-ref-management-in-function-components">Ref as a Prop: Simplifying Ref Management in Function Components</h2>
<p>React 19 introduces the ability to pass a ref as a regular prop to a function component. This simplifies ref management, especially when working with reusable components or needing to access DOM elements within deeply nested component structures. It eliminates the need for <code>forwardRef</code> in many common scenarios, leading to cleaner and more concise code.</p>
<h3 id="heading-the-problem-with-traditional-ref-management-in-function-components">The Problem with Traditional Ref Management in Function Components</h3>
<p>Traditionally, If you needed to access a DOM element inside a function component inside a parent component, you had to use <code>forwardRef</code>. This added a bit of boilerplate and could make the code slightly more complex, especially for simple cases.</p>
<p>Consider a reusable input component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { forwardRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> MyInput = forwardRef(<span class="hljs-function">(<span class="hljs-params">props, ref</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{ref}</span> {<span class="hljs-attr">...props</span>} /&gt;</span></span>
));

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ParentComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> inputRef = React.useRef(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (inputRef.current) {
      inputRef.current.focus();
    }
  }, []);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">MyInput</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter text"</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{inputRef}</span> /&gt;</span></span>;
}
</code></pre>
<p>In this example, <code>forwardRef</code> is necessary to pass the <code>ref</code> from <code>ParentComponent</code> down to the underlying <code>&lt;input&gt;</code> element in <code>MyInput</code>. While this works, it adds extra code and can be slightly confusing for simpler use cases.</p>
<h3 id="heading-simplifying-ref-management-with-ref-as-a-prop">Simplifying Ref Management with Ref as a Prop</h3>
<p>React 19 simplifies this by allowing you to pass ref as a regular prop to function components. This means you no longer need <code>forwardRef</code> in many common scenarios.</p>
<p>The previous example can now be written as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> MyInput = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{props.ref}</span> {<span class="hljs-attr">...props</span>} /&gt;</span></span>
);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ParentComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> inputRef = React.useRef(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (inputRef.current) {
      inputRef.current.focus();
    }
  }, []);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">MyInput</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter text"</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{inputRef}</span> /&gt;</span></span>;
}
</code></pre>
<p>As you can see, <code>forwardRef</code> is no longer needed. The <code>ref</code> prop is passed directly to the <code>MyInput</code> component and then forwarded to the underlying <code>&lt;input&gt;</code> element.</p>
<p><strong>Important Considerations</strong></p>
<ul>
<li><p><strong>Explicitly Forwarding the Ref:</strong> It’s crucial that the function component explicitly forwards the <code>ref</code> prop to the underlying DOM element or component that needs it. If the <code>ref</code> prop isn't used within the function component, it won't work as expected.</p>
</li>
<li><p><strong>Caveats with Class Components:</strong> This new feature only applies to function components. You still need <code>forwardRef</code> when working with class components.</p>
</li>
<li><p><strong>Use Cases where forwardRef is still needed:</strong> If you need to manipulate the ref before passing it down (e.g. adding a custom property to the ref object) you will still need <code>forwardRef</code>.</p>
</li>
</ul>
<p><strong>Benefits of Ref as a Prop</strong></p>
<ul>
<li><p><strong>Simplified Syntax:</strong> Eliminates the need for <code>forwardRef</code> in many common cases, making the code shorter and easier to read.</p>
</li>
<li><p><strong>Improved Readability:</strong> The code is more straightforward and easier to understand, especially for simple ref usage.</p>
</li>
<li><p><strong>Reduced Boilerplate:</strong> Reduces the amount of code required to manage refs in function components.</p>
</li>
<li><p><strong>More Intuitive API:</strong> Makes ref management more consistent with other prop passing mechanisms.</p>
</li>
</ul>
<p>By allowing <code>ref</code> to be passed as a regular prop, React 19 simplifies ref management in function components, leading to cleaner, more concise, and more readable code. This change streamlines a common pattern in React development and contributes to a smoother developer experience.</p>
<h2 id="heading-cleanup-functions-for-refs-ensuring-proper-cleanup-and-resource-management">Cleanup Functions for Refs: Ensuring Proper Cleanup and Resource Management</h2>
<p>React 19 provides cleanup functions for refs, addressing potential memory leaks and ensuring proper resource management, especially when working with imperative APIs or external libraries. This enhancement provides a more robust and predictable way to handle resources associated with refs.</p>
<h3 id="heading-the-problem-with-traditional-ref-management">The Problem with Traditional Ref Management</h3>
<p>Traditionally, ref provides a way to access the underlying DOM element or a component instance. However, there is no built-in mechanism to perform cleanup when the component is unmounted or the ref changed. This could lead to issues in certain scenarios:</p>
<ul>
<li><p><strong>Memory Leaks</strong>: if a ref was used to create subscription event listeners or external resources, these resources might not be released when the component is unmounted, leading to memory leaks.</p>
</li>
<li><p><strong>Stale References</strong>: If a ref pointed to a DOM element that was removed from the DOM, accessing it could lead to errors.</p>
</li>
<li><p><strong>Unpredictable Behavior</strong>: Without cleanup, the behavior of components using refs could become unpredictable, especially in complex applications with dynamic rendering.</p>
</li>
</ul>
<p>Consider a scenario where you are integrating with a third-party charting library that requires a DOM element to render a chart:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useRef, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ChartLibrary <span class="hljs-keyword">from</span> <span class="hljs-string">'external-chart-library'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyChart</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> chartRef = useRef(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (chartRef.current) {
      <span class="hljs-keyword">const</span> chart = <span class="hljs-keyword">new</span> ChartLibrary.Chart(chartRef.current, { <span class="hljs-comment">/* chart options */</span> });
      <span class="hljs-comment">// No cleanup here! Potential memory leak</span>
    }
  }, []);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{chartRef}</span> /&gt;</span></span>;
}
</code></pre>
<p>In this example, if the MyChart component unmounts, the chart instance created by the third-party library might not be properly destroyed, leading to memory leaks.</p>
<h3 id="heading-enhancing-refs-with-cleanup-functions">Enhancing Refs with Cleanup Functions</h3>
<p>React 19 addresses these issues by allowing you to provide a cleanup function when setting a ref. This cleanup function will be called when the component unmounts or when the ref changes to a different element.</p>
<p>You can now pass a function to the ref callback. This function will be called with the old ref value when it changes or when the component unmounts.</p>
<pre><code class="lang-javascript">&lt;div ref={<span class="hljs-function">(<span class="hljs-params">node</span>) =&gt;</span> {
    <span class="hljs-comment">// Set the ref</span>
    myRef.current = node;
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-comment">// Cleanup logic here. 'node' is the old value</span>
        <span class="hljs-keyword">if</span>(node) {
            <span class="hljs-comment">// e.g. node.removeEventListener(...) or destroy external instance</span>
        }
    }
}} /&gt;

<span class="hljs-keyword">import</span> { useRef, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ChartLibrary <span class="hljs-keyword">from</span> <span class="hljs-string">'external-chart-library'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyChart</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> chartRef = useRef(<span class="hljs-literal">null</span>);
    <span class="hljs-keyword">const</span> chartInstance = useRef(<span class="hljs-literal">null</span>)

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span>(chartInstance.current) {
            chartInstance.current.destroy() <span class="hljs-comment">// Properly destroy the chart</span>
        }
    }
  }, [])

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{(node)</span> =&gt;</span> {
      if(node) {
          chartInstance.current = new ChartLibrary.Chart(node, { /* chart options */ });
      }
      return () =&gt; {
          if(chartInstance.current) {
              chartInstance.current.destroy()
              chartInstance.current = null
          }
      }
  }} /&gt;</span>;
}
</code></pre>
<p>Now, when <code>MyChart</code> component unmounts, the cleanup function will be called, destroying the chart instance and preventing a memory leak.</p>
<h3 id="heading-benefits-of-cleanup-functions-for-refs">Benefits of Cleanup Functions for Refs</h3>
<ul>
<li><p><strong>Prevent memory leaks</strong>: Ensures that resources associated with refs are properly released</p>
</li>
<li><p><strong>Avoid stale references</strong>: Prevents errors caused by accessing the DOM element that has been removed.</p>
</li>
<li><p><strong>Improved resource management</strong>: Provides a more robust and predictable way to manage resources.</p>
</li>
<li><p><strong>Cleaner code</strong>: Makes code that interacts with imperative APIs or external libraries cleaner and easier to reason about.</p>
</li>
</ul>
<p>By adding cleanup functions for refs, React 19 provides a crucial mechanism for ensuring proper resource management and preventing potential issues related to memory leaks and slate references. This enhancement makes React a more robust and reliable platform for building complex applications.</p>
<h2 id="heading-built-in-document-metadata-support">Built-in Document Metadata Support</h2>
<p>React 19 simplifies SEO by adding built-in support for managing metadata like titles, descriptions, and meta tags. Previously, developers had to rely on libraries like <code>react-helmet</code> for this functionality. Now, React handles it out of the box.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata = {
  title: <span class="hljs-string">'React 19 Stable Release'</span>,
  description: <span class="hljs-string">'Discover the features of React 19 and how it improves development.'</span>,
};
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> &lt;h1&gt;Hello, React <span class="hljs-number">19</span>!&lt;/h1&gt;;
}
</code></pre>
<h2 id="heading-react-192">React 19.2</h2>
<p>React 19.2.0 introduces significant enhancements that refine how you manage component life cycle, optimize rendering performance, and streamline server-side rendering workflows. This release, the third in the last year following React 19 and React 19.1, equips developers with powerful new primitives to build faster, more-efficient, and state-preserving applications.</p>
<p>Let's dive into the latest updates, exploring how they will help you revolutionize your development and boost application efficiency.</p>
<h3 id="heading-activity-control-component-visibility-and-prioritization">Activity: Control Component Visibility and Prioritization</h3>
<p>The new <code>&lt;Activity/&gt;</code> component provides a new mechanism to partition an application into distinct “activities“, each of which can be prioritized and managed separately. It offers a more advanced solution than basic conditional rendering, especially when a persistent state is required for elements not currently in the viewport.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Before</span>
{isVisible &amp;&amp; &lt;Page /&gt;}

<span class="hljs-comment">// After</span>
&lt;Activity mode={isVisible ? <span class="hljs-string">'visible'</span> : <span class="hljs-string">'hidden'</span>}&gt;
  &lt;Page /&gt;
&lt;/Activity&gt;
</code></pre>
<p><strong>React 19.2 supports two primary modes for</strong> <code>&lt;Activity&gt;</code><strong>:</strong></p>
<ul>
<li><p><strong>hidden:</strong> The children are hidden, their effects are unmounted, and all updates are deferred until React has nothing left to work on.</p>
</li>
<li><p><strong>visible:</strong> The children are shown, effects are mounted, and updates are processed normally.</p>
</li>
</ul>
<p>This capability is perfect for background work, allowing you to preload components or data needed for the next navigation step, or to retain form input and or scroll positions when the user switches from the view.</p>
<p><a target="_blank" href="https://amit08255.medium.com/the-secret-to-preserving-state-without-sacrificing-performance-in-react-3e7d397a849c">https://amit08255.medium.com/the-secret-to-preserving-state-without-sacrificing-performance-in-react-3e7d397a849c</a></p>
<h3 id="heading-useeffectevent-separating-events-from-effects">useEffectEvent: Separating Events from Effects</h3>
<p>A frequent source of complexity is the necessity to list props or state variables in the useEffect dependency arrays, often causing the Effect to needlessly re-run. The new <code>useEffectEvent</code> hook resolves this by allowing you to define a callback function—conceptually an "event handler"—that operates outside the Effect's dependency tracking.</p>
<p>Functions created with <code>useEffectEvent</code> always reference the freshest props and state, but are explicitly not considered dependencies of the hosting Effect.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ChatRoom</span>(<span class="hljs-params">{ roomId, theme }</span>) </span>{
  <span class="hljs-keyword">const</span> onConnected = useEffectEvent(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// This function always gets the latest 'theme' without</span>
    <span class="hljs-comment">// causing the effect below to re-run on theme changes.</span>
    showNotification(<span class="hljs-string">'Connected!'</span>, theme);
  });

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> connection = createConnection(serverUrl, roomId);
    connection.on(<span class="hljs-string">'connected'</span>, <span class="hljs-function">() =&gt;</span> {
      onConnected(); <span class="hljs-comment">// calls the event function</span>
    });
    connection.connect();
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> connection.disconnect();
  }, [roomId]); <span class="hljs-comment">// ✅ 'onConnected' is correctly excluded</span>
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p><strong><em>Note:</em></strong> <em>Developers must update their tooling to</em> <code>eslint-plugin-react-hooks@6.1.0</code><em>o correctly incorporate this new primitive and enforce its usage rules.</em></p>
<p><a target="_blank" href="https://4markdown.com/react-useeffectevent-a-new-dimension-for-reusable-hooks/">https://4markdown.com/react-useeffectevent-a-new-dimension-for-reusable-hooks/</a></p>
<h3 id="heading-cachesignal-for-server-component-resource-management">cacheSignal for Server Component Resource Management</h3>
<p>Available exclusively within React Server Components, the <code>cacheSignal</code> utility returns an <code>AbortSignal</code>. This signal is crucial for resource hygiene as it triggers precisely when the component's <code>cache()</code> scope expires, allowing developers to immediately halt or clean up any ongoing asynchronous operations (like an extended data fetch).</p>
<ul>
<li><p>The signal provides lifecycle management for deduped operations, firing when:</p>
</li>
<li><p>The rendering successfully completes.</p>
</li>
<li><p>The rendering process is explicitly aborted.</p>
</li>
<li><p>The rendering encounters a failure.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {cache, cacheSignal} <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">const</span> dedupedFetch = cache(fetch);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Component</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">await</span> dedupedFetch(url, { signal: cacheSignal() });
}
</code></pre>
<h1 id="heading-react-18">React 18</h1>
<p><a target="_blank" href="https://betterprogramming.pub/the-complete-guide-to-react-18-dd8763430345">React 18 was released</a> on March 29, 2022. React provides many exciting features that are out of the box. These are not only enhancing the user experience but also making de lives easier. So, here are three main features that are going to be released this time.</p>
<h2 id="heading-a-big-challenge-with-a-react-application">A Big Challenge with a React Application</h2>
<h3 id="heading-concurrency">Concurrency</h3>
<p>Concurrency is a major challenge for heavy React apps. In a React app, concurrency can arise when multiple components render simultaneously, when different parts of the app perform complex tasks concurrently, or when network requests are made concurrently.</p>
<p>Managing concurrently effectively requires careful planning and coordination to ensure that the app’s components and processes work together seamlessly and avoid conflicts or race conditions. Without proper handling of concurrency, a React app may experience performance issues, crashes, or other problems.</p>
<h3 id="heading-improper-setstate-usage">Improper setState Usage</h3>
<p>Improper use of the <code>setState</code> method in the React app can lead to performance degradation because it can trigger unnecessary re-renders of components. <strong>When</strong> <code>setState</code> <strong>is called, it triggers a re-render of the component and all of its children, which can be computationally expensive</strong> if the component tree is large or if the components have expensive render methods.</p>
<p>To avoid unnecessary re-renders and improve performance, it’s important to use <code>setState</code> judiciously and only when necessary, and to consider using alternative methods such as <code>useReducer</code> or <code>useState</code> with functional updates to minimize the number of re-renders. Properly managing the use <code>setState</code> can help ensure that your React app remains performant and responsive.</p>
<h2 id="heading-react-concurrent-mode">React Concurrent Mode</h2>
<p>React Concurrent Mode is a cutting-edge feature designed to transform the way React applications handle rendering, bringing a new level of responsiveness and performance. Unlike the traditional synchronous rendering mode, where React processes updates sequentially, the Concurrent Mode enables the framework to manage multiple tasks simultaneously. This allows React to interrupt and prioritize tasks based on user interactions, ensuring that the UI remains fluid even during intensive computations.</p>
<h3 id="heading-key-concepts-in-concurrent-mode">Key Concepts in Concurrent Mode</h3>
<ol>
<li><p><strong>Time Slicing</strong>: Time Slicing is a fundamental feature of Concurrent Mode. It enables React to divide rendering work into small, manageable units that can be spread across multiple frames. This ensures that the main thread remains unblocked, allowing high-priority tasks like user interactions or animations to be handled promptly. Time Slicing allows React to work on the UI in segments, pausing to address more urgent tasks before resuming where it left off. This results in a smoother and more responsive user experience.</p>
</li>
<li><p><strong>Suspense for Data Fetching</strong>: Suspend is another powerful feature that complements Concurrent Mode. It allows React to “suspend“ the rendering of a component until a specific asynchronous, such as data fetching, is complete. During this waiting period, React can continue rendering other parts of a UI or displaying a fallback component (like a loading spinner) to keep the user informed. When combined with Concurrent Mode, Suspense significantly enhances the user experience, particularly in applications that rely heavily on asynchronous data fetching.</p>
</li>
<li><p><strong>Interruptible Rendering</strong>: Interruptible is a game-changing concept for maintaining a responsive UI. In traditional React, rendering can not be interrupted once it starts, leading to potential UI freezes. Concurrent Mode allows React to interrupt rendering to prioritize higher-priority updates. For instance, if the user interacts with the UI while React is rendering, React can pause the current rendering process, handle the interaction, and then resume rendering. This capability ensures that user interactions are reflected in the UI without delay, leading to a more responsive application.</p>
</li>
<li><p><strong>Selective Hydration</strong>: Selective Hydration is an advanced concept within Concurrent Mode, particularly useful in server-side rendering (SSR) scenarios. It allows React to hydrate (i.e, make interactive) only the parts of the page currently visible to the users, deferring less critical sections until they are in view. This prioritization improves the perceived loading time of the application.</p>
</li>
</ol>
<p><strong>Example: Time Slicing</strong></p>
<p>Consider an application that needs to render a large list of items. Without Concurrent Mode, rendering a large list could cause the UI to freeze, leading to a poor user experience. With Concurrent Mode, React can break down the rendering process into smaller tasks that are processed over multiple frames, maintaining UI responsiveness.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ListItem</span>(<span class="hljs-params">{ item }</span>) </span>{
  <span class="hljs-comment">// Simulate heavy computation</span>
  <span class="hljs-keyword">let</span> now = performance.now();
  <span class="hljs-keyword">while</span> (performance.now() - now &lt; <span class="hljs-number">20</span>) {
    <span class="hljs-comment">// Block CPU for 20ms</span>
  }
  <span class="hljs-keyword">return</span> &lt;div&gt;{item}&lt;/div&gt;;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [items] = useState(<span class="hljs-built_in">Array</span>.from({ length: <span class="hljs-number">1000</span> }, <span class="hljs-function">(<span class="hljs-params">_, i</span>) =&gt;</span> <span class="hljs-string">`Item <span class="hljs-subst">${i + <span class="hljs-number">1</span>}</span>`</span>));
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {items.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> (
        &lt;ListItem key={item} item={item} /&gt;
      ))}
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>In this example, rendering 1000 items might normally cause noticeable lag. However, with Concurrent Mode, React slices the work into smaller, manageable chunks that are processed over multiple frames, ensuring that the UI remains responsive throughout.</p>
<p><strong>Example: Suspense for Data Fetching</strong></p>
<p>Suspense allows you to defer the rendering of a component until its required data is loaded, preventing the UI from being blocked while waiting for asynchronous operations to complete. This enhances the overall user experience by providing immediate feedback.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> React, { Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> fetchData = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> {
    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> resolve(<span class="hljs-string">'Data loaded'</span>), <span class="hljs-number">3000</span>);
  });
};

<span class="hljs-keyword">const</span> DataComponent = React.lazy(<span class="hljs-function">() =&gt;</span> fetchData().then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> ({
  <span class="hljs-keyword">default</span>: <span class="hljs-function">() =&gt;</span> &lt;div&gt;{data}&lt;/div&gt;,
})));

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;Suspense fallback={&lt;div&gt;Loading…&lt;/div&gt;}&gt;
        &lt;DataComponent /&gt;
      &lt;/Suspense&gt;
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here, <code>DataComponent</code> is a lazy-loaded component that fetches data. The <code>Suspense</code> component wraps <code>DataComponent</code> and provides a fallback UI <code>(Loading…)</code> while the data is being fetched. With Concurrent Mode, React can continue rendering other parts of the UI while waiting for the data to load, improving perceived performance.</p>
<h3 id="heading-how-to-enable-concurrent-mode">How to Enable Concurrent Mode</h3>
<p>Concurrent Mode is currently an experimental feature and must be explicitly enabled in your application. Here’s how you can set it up:</p>
<ol>
<li>**Install React Experimental Versions:<br /> **You need to use the experimental versions of React to enable Concurrent Mode.</li>
</ol>
<pre><code class="lang-typescript">npm install react<span class="hljs-meta">@experimental</span> react-dom<span class="hljs-meta">@experimental</span>
</code></pre>
<p><strong>2. Enable Concurrent Mode in Your Root Component:</strong><br />Wrap your root component with <code>createRoot</code> and set the <code>concurrent</code> flag to <code>true</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>), { concurrent: <span class="hljs-literal">true</span> }).render(&lt;App /&gt;);
</code></pre>
<h3 id="heading-additional-information">Additional Information</h3>
<ul>
<li><p><strong>Gradual Adoption:</strong> Concurrent Mode can be adopted incrementally. As it is still experimental, it’s wise to apply it to smaller parts of your application first. This approach allows you to assess the impact on performance and responsiveness before fully integrating it into your app.</p>
</li>
<li><p><strong>Development Tools:</strong> New developer tools are available with Concurrent Mode to help visualize how React prioritizes and handles tasks. These tools are invaluable for debugging performance issues and understanding the improvements Concurrent Mode brings to your application.</p>
</li>
<li><p><strong>Compatibility:</strong> Since Concurrent Mode is still in the experimental phase, some third-party libraries may not fully support it yet. It’s important to test and ensure compatibility with the libraries used in your application.</p>
</li>
</ul>
<h2 id="heading-automatic-batching">Automatic Batching</h2>
<p>Batching is when React groups multiple state updates into a single re-render for better performance.</p>
<p>For example, if you have 2 state updates inside of the same click event, React has always batched these into one re-render. If you run the following code, you will see that every time you click, React only performs only render, although you set the state twice.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735571146654/87b9f644-f038-4fca-8b4f-be359494ada6.webp" alt class="image--center mx-auto" /></p>
<p>This is great for performance because it avoids unnecessary re-renders. It also prevents your component from rendering “half-finished“ states where only one state variable was updated, which may cause bugs. This might remind you of how a restaurant waiter doesn’t run to the kitchen when you choose the first dish, but waits for you to finish your order.</p>
<p>However, React wasn’t consistent about when it batches updates. For example, if you need to fetch data and then update the state in the <code>handleClick</code> above, the React would not batch the updates and perform two independent updates.</p>
<p>This is because React used to batch update only during a browser event (like a click), but here, we are updating the state after the event has already been handled (in the fetch callback).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735572178125/c229d82f-d222-486c-9b5e-b27725d88ec1.webp" alt class="image--center mx-auto" /></p>
<p>In automatic batching (after upgrading to React 18), no matter where the states originate, they will always be re-rendered once.</p>
<h3 id="heading-what-if-i-dont-want-to-batch">What if I don’t want to batch?</h3>
<p>In this case, you will have to use <code>flushSync</code> in order to re-render the component.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735573039244/d68bebcb-7322-4446-9b5a-4ca983ef5207.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-ssr-support-for-suspense">SSR support for Suspense</h2>
<p><a target="_blank" href="https://www.freecodecamp.org/news/the-nextjs-15-streaming-handbook/?ref=dailydev">https://www.freecodecamp.org/news/the-nextjs-15-streaming-handbook/?ref=dailydev</a></p>
<h3 id="heading-the-loading-problem-with-traditional-react">The Loading Problem with Traditional React</h3>
<p>Not long ago, most React apps relied entirely on client-side rendering. You would show a spinner, wait for data to load, and finally render your UI. Later, with frameworks like Next.js, SSR (server-side rendering) became mainstream, mostly for performance and SEO. But this came at a cost:</p>
<ol>
<li><p>You had to fetch everything before you could show anything (fetch data for the entire app and send the HTML)</p>
</li>
<li><p>You had to load everything before you could hydrate anything (on the client, load the JavaScript for the entire app)</p>
</li>
<li><p>You had to hydate everything before you could interact with anything (add JavaScript to all pre-built HTML on the server)</p>
</li>
</ol>
<p>The main problem was that all these steps had to be done before each other, so the next step could start. This was not efficient. Why did the user have to wait for everything to load just to click on a button on the sidebar?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755255586754/096287dc-c5a0-45bd-8698-b522ed101609.webp" alt class="image--center mx-auto" /></p>
<p>That is where React Suspend and its streaming model came in, not to break its waterfall but to rethink its ways of making a user-first experience. React changed the game by letting us perform these steps independently — per component — instead of waiting for the whole app.</p>
<h3 id="heading-how-react-suspense-transforms-loading">How React Suspense Transforms Loading</h3>
<p>There are two major changes in React 18 unlocked by Suspense:</p>
<ol>
<li><p>Streaming HTML on the server</p>
</li>
<li><p>Selective hydration of the client</p>
</li>
</ol>
<p>Imagine that we have a website that has a <code>Header</code>, <code>Sidebar</code>, <code>Blogs</code>, and a <code>Project</code> section. With the traditional approach, we had to first render all HTML like this:</p>
<pre><code class="lang-typescript">&lt;main&gt;
      &lt;header className=<span class="hljs-string">"h-20 bg-gray-200 flex items-center justify-center"</span>&gt;
        &lt;ul className=<span class="hljs-string">"flex items-center justify-center gap-x-4"</span>&gt;
          &lt;li&gt;home&lt;/li&gt;
          &lt;li&gt;blogs&lt;/li&gt;
          &lt;li&gt;projects&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/header&gt;
      &lt;section className=<span class="hljs-string">"border border-black space-y-10"</span>&gt;
              &lt;header&gt;
                &lt;h1 className=<span class="hljs-string">"font-bold text-2xl"</span>&gt;Hello Streaming&lt;/h1&gt;
              &lt;/header&gt;
              &lt;div className=<span class="hljs-string">"flex border gap-5 border-red-500"</span>&gt;
                &lt;aside className=<span class="hljs-string">"w-full max-w-[300px] flex items-center justify-center bg-gray-200"</span>&gt;
                  sidebar
                &lt;/aside&gt;
                &lt;section className=<span class="hljs-string">"flex-[1] space-y-5"</span>&gt;
                  &lt;div className=<span class="hljs-string">"h-40 bg-gray-200 flex items-center justify-center"</span>&gt;
                    projects
                  &lt;/div&gt;
                  &lt;div className=<span class="hljs-string">"h-40 bg-gray-200 flex items-center justify-center"</span>&gt;
                    blogs
                  &lt;/div&gt;
                &lt;/section&gt;
              &lt;/div&gt;
       &lt;/section&gt;
    &lt;/main&gt;
</code></pre>
<p>And the client would eventually get this as a result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755255930067/05b62c85-0cc5-4ddc-a2a7-a1c428d0cae7.webp" alt class="image--center mx-auto" /></p>
<p>When the JavaScript was sent and loaded on the client, the event handlers and everything were attached to the DOM items, and they would become responsive to interactions. This process is called Hydration. The outcome would be like this — by green color, I mean the section is totally interactive.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755256177620/fc005f48-68cc-4cda-a53d-3358c573e44c.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-stream-ssr-breaking-the-loading-bottleneck">Stream SSR: Breaking the Loading Bottleneck</h3>
<p>Before diving into Suspense and Fallback UIs, it’s important to understand how React enables streaming in the first place. Under the hood, React uses a function called <code>renderToPipeableStream()</code> which begins rendering HTML immediately as a stream instead of waiting for the entire tree to be ready. This allows the server to send HTML to the browser in chunks, unlocking partial rendering and faster Time To First Byte (TTFB).</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { renderToPipeableStream } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/server'</span>;

<span class="hljs-keyword">const</span> { pipe } = renderToPipeableStream(&lt;App /&gt;, {
  onShellReady() {
    pipe(response);
  },
});
</code></pre>
<p>This function is the backbone of streaming SSR — it lets React “flush“ whatever part of the HTML is ready and postpone slower parts (like <code>Suspense</code> boundaries) for later. Use it in server frameworks like Express or Node handlers.</p>
<p>So, with the new model, we can wrap a part of our page within <code>Suspense</code>. For example, the <code>Blogs</code> component. This <code>Suspense</code> gets a fallback prop that accepts the UI to be shown in place of the main component.</p>
<pre><code class="lang-typescript">&lt;main&gt;
      &lt;header className=<span class="hljs-string">"h-20 bg-gray-200 flex items-center justify-center"</span>&gt;
        &lt;ul className=<span class="hljs-string">"flex items-center justify-center gap-x-4"</span>&gt;
          &lt;li&gt;home&lt;/li&gt;
          &lt;li&gt;blogs&lt;/li&gt;
          &lt;li&gt;projects&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/header&gt;
&lt;section className=<span class="hljs-string">"border border-black space-y-10"</span>&gt;
        &lt;header&gt;
          &lt;h1 className=<span class="hljs-string">"font-bold text-2xl"</span>&gt;Hello Streaming&lt;/h1&gt;
        &lt;/header&gt;
        &lt;div className=<span class="hljs-string">"flex border gap-5 border-red-500"</span>&gt;
          &lt;aside className=<span class="hljs-string">"w-full max-w-[300px] flex items-center justify-center bg-gray-200"</span>&gt;
            sidebar
          &lt;/aside&gt;
          &lt;section className=<span class="hljs-string">"flex-[1] space-y-5"</span>&gt;
            &lt;div className=<span class="hljs-string">"h-40 bg-gray-200 flex items-center justify-center"</span>&gt;
              projects
            &lt;/div&gt;
            &lt;Suspense fallback={&lt;div&gt;Loading blogs...&lt;/div&gt;}&gt;
              &lt;Blogs /&gt;
            &lt;/Suspense&gt;
          &lt;/section&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/main&gt;
</code></pre>
<p>What does the above code mean? It will tell React that it does not have to wait for the <code>Blogs</code> content to start streaming the HTML for the rest of the page. So, show the fallback UI instead, and will send this:</p>
<pre><code class="lang-typescript">&lt;main&gt;
      &lt;header className=<span class="hljs-string">"h-20 bg-gray-200 flex items-center justify-center"</span>&gt;
        &lt;ul className=<span class="hljs-string">"flex items-center justify-center gap-x-4"</span>&gt;
          &lt;li&gt;home&lt;/li&gt;
          &lt;li&gt;blogs&lt;/li&gt;
          &lt;li&gt;projects&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/header&gt;
&lt;section className=<span class="hljs-string">"border border-black space-y-10"</span>&gt;
        &lt;header&gt;
          &lt;h1 className=<span class="hljs-string">"font-bold text-2xl"</span>&gt;Hello Streaming&lt;/h1&gt;
        &lt;/header&gt;
        &lt;div className=<span class="hljs-string">"flex border gap-5 border-red-500"</span>&gt;
          &lt;aside className=<span class="hljs-string">"w-full max-w-[300px] flex items-center justify-center bg-gray-200"</span>&gt;
            sidebar
          &lt;/aside&gt;
          &lt;section className=<span class="hljs-string">"flex-[1] space-y-5"</span>&gt;
            &lt;div className=<span class="hljs-string">"h-40 bg-gray-200 flex items-center justify-center"</span>&gt;
              projects
            &lt;/div&gt;
             &lt;!--$?--&gt;
                &lt;template id=<span class="hljs-string">"B:0"</span>&gt;&lt;/template&gt;
                &lt;div&gt;Loading blogs...&lt;/div&gt;
             &lt;!--/$--&gt;
          &lt;/section&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/main&gt;
</code></pre>
<p>The result of this will be.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755256711455/c74cc3b2-8a94-4ad4-8b3e-bca34f75a74e.webp" alt class="image--center mx-auto" /></p>
<p>But the story doesn’t end here. When the page first loads, React inserts a fallback — like a loading skeleton and assigns it a unique ID, such as <code>id="B:0"</code>. Meanwhile, the <strong>real content</strong> (for example, the blog posts) is still being processed and streamed.</p>
<p>Once it’s ready, React includes it in the ongoing HTML stream, along with a lightweight &lt;script&gt; that handles the magic: replacing the placeholder (<code>B:0</code>) with the actual content.</p>
<p>This makes the transition feel smooth and effortless to the user — no full rerenders, no flickers, just progressive enhancement.</p>
<pre><code class="lang-typescript">&lt;script&gt;
            self.__next_f.push([<span class="hljs-number">1</span>, <span class="hljs-string">"25:[\"$\",\"div\",null,{\"children\":\"✅ Comments loaded!\"},\"$26\",[[\"Comments\",\"file:///C:/Users/Abolfazl/Desktop/cache-practice/.next/server/chunks/ssr/src__components_comments_tsx_436f2c30._.js\",15,263]],1]\n"</span>])
        &lt;/script&gt;
        &lt;div hidden id=<span class="hljs-string">"S:0"</span>&gt;
            &lt;div&gt;✅ Comments loaded!&lt;/div&gt;
        &lt;/div&gt;
        &lt;script&gt;
            $RC = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">b, c, e</span>) </span>{
                c = <span class="hljs-built_in">document</span>.getElementById(c);
                c.parentNode.removeChild(c);
                <span class="hljs-keyword">var</span> a = <span class="hljs-built_in">document</span>.getElementById(b);
                <span class="hljs-keyword">if</span> (a) {
                    b = a.previousSibling;
                    <span class="hljs-keyword">if</span> (e)
                        b.data = <span class="hljs-string">"$!"</span>,
                        a.setAttribute(<span class="hljs-string">"data-dgst"</span>, e);
                    <span class="hljs-keyword">else</span> {
                        e = b.parentNode;
                        a = b.nextSibling;
                        <span class="hljs-keyword">var</span> f = <span class="hljs-number">0</span>;
                        <span class="hljs-keyword">do</span> {
                            <span class="hljs-keyword">if</span> (a &amp;&amp; <span class="hljs-number">8</span> === a.nodeType) {
                                <span class="hljs-keyword">var</span> d = a.data;
                                <span class="hljs-keyword">if</span> (<span class="hljs-string">"/$"</span> === d)
                                    <span class="hljs-keyword">if</span> (<span class="hljs-number">0</span> === f)
                                        <span class="hljs-keyword">break</span>;
                                    <span class="hljs-keyword">else</span>
                                        f--;
                                <span class="hljs-keyword">else</span>
                                    <span class="hljs-string">"$"</span> !== d &amp;&amp; <span class="hljs-string">"$?"</span> !== d &amp;&amp; <span class="hljs-string">"$!"</span> !== d || f++
                            }
                            d = a.nextSibling;
                            e.removeChild(a);
                            a = d
                        } <span class="hljs-keyword">while</span> (a);
                        <span class="hljs-keyword">for</span> (; c.firstChild; )
                            e.insertBefore(c.firstChild, a);
                        b.data = <span class="hljs-string">"$"</span>
                    }
                    b._reactRetry &amp;&amp; b._reactRetry()
                }
            }
            ;
            $RC(<span class="hljs-string">"B:0"</span>, <span class="hljs-string">"S:0"</span>)
        &lt;/script&gt;
</code></pre>
<p>During streaming, React inserts the fallback UI in the HTML where the content isn’t ready yet. Later, when that content becomes available, React sends a small <code>&lt;script&gt;</code> like this: <code>$RC("B:0", "S:0")</code></p>
<p>In this script:</p>
<ul>
<li><p><code>B:0</code> refers to the <strong>placeholder block</strong> (like your loading spinner)</p>
</li>
<li><p><code>S:0</code> Is the <strong>actual content</strong> to be inserted</p>
</li>
</ul>
<p>React’s client-side runtime uses an internal function <code>decodeReply()</code> to manage incoming streamed data and match it with placeholders created during rendering.</p>
<p>This function is responsible for:</p>
<ul>
<li><p>Receiving streamed segments (like blog post content)</p>
</li>
<li><p>Locating the right fallback (like B:0)</p>
</li>
<li><p>Replacing it in the DOM, without rerendering the full page</p>
</li>
</ul>
<p>It’s a part of React’s internal streaming runtime and not something you use manually, but understanding it helps connect the dots between the fallback you see on screen and the moment it’s seamlessly replaced by the real content.</p>
<p>While this isn’t exposed directly, you can observe its behaviors through <code>&lt;script/&gt;</code> tags injected during server-side streaming, which execute logic like:</p>
<pre><code class="lang-typescript">&lt;script&gt;
  $RC(<span class="hljs-string">"B:0"</span>, <span class="hljs-string">"S:0"</span>)
&lt;/script&gt;
</code></pre>
<p>💡 This is what makes the streaming experience feel seamless — your UI gradually fills in, piece by piece, as content becomes ready. This process will solve the first problem we had (You have to fetch everything before you can show anything).</p>
<h3 id="heading-selective-hydration-fast-interaction-where-it-counts">Selective Hydration: Fast Interaction Where It Counts</h3>
<p>Now, even if we streamed the initial HTML quickly, there’s still a problem: The page can’t become fully interactive until the JavaScript bundle for each widget (like the blog post list) is downloaded and executed. If that JS is large, hydration will be delayed, and so will user interaction. To solve this, we use code splitting. It lets us separate parts of the app into smaller bundles. That way, low-priority features can load later, improving initial load time. For example, you can use <code>React.lazy()</code> to split the <code>Blogs</code> section out of the main bundle and load it only when needed.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { lazy, Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">const</span> Blogs = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">"../_components/comments"</span>));

&lt;Suspense fallback={&lt;div&gt;Loading blogs ...&lt;/div&gt;}&gt;
    &lt;Blogs /&gt;
&lt;/Suspense&gt;
</code></pre>
<p>React 18 changes the game: even if the blog posts haven’t loaded yet, hydration can begin. The result? From the user’s perspective, the page starts responding much sooner — no more waiting for all components to be ready.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755259317350/47e955d5-4d2b-4b9d-9a5b-43c821d44877.webp" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755259368755/b69dc0ae-c642-462b-b067-8283ab92dc73.webp" alt class="image--center mx-auto" /></p>
<p>Since the blog post code isn’t available yet, React doesn’t wait around. It hydrates the parts of the UI that are ready — like the navigation or footer — so the user can interact with them immediately.</p>
<p>This is a clear example of <strong>Selective Hydration</strong> in action. By wrapping the blog post section in a <code>&lt;Suspense&gt;</code> boundary, you're telling React:<br /><em>"Don't let this part block the rest of the page."</em> And React takes it one step further — it doesn’t just continue streaming the rest of the HTML; it also starts <strong>hydrating</strong> other parts of the page immediately.</p>
<p>💡 That solves a major bottleneck: you no longer need to wait for all JavaScript to load before hydration begins. Instead, React hydrates what’s ready and returns to the rest once its code finishes loading.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755259598241/7c206e45-d03e-4503-867f-b235192c8024.webp" alt class="image--center mx-auto" /></p>
<p>The beauty of it is that React handles all of this for you automatically. Let’s say the HTML is delayed, but the JavaScript bundle arrives first. React doesn’t wait. It begins by hydrating the parts of the page that are ready, even if some HTML hasn’t been received yet. This ensures your app becomes interactive as soon as possible, without blocking slower sections.</p>
<h3 id="heading-bonus-smarter-hydration-for-smoother-interaction">Bonus: Smarter Hydration for Smoother Interaction</h3>
<p>When we wrapped the blog posts in a <code>&lt;Suspense&gt;</code> boundary, something subtle but powerful also happened behind the scenes. <strong>Their hydration no longer blocks the browser from handling other tasks.</strong> For example, imagine the blog posts are still being hydrated, and the user clicks on the sidebar. In React 18, hydration inside Suspense boundaries happens in small chunks, allowing the browser to briefly <strong>pause React’s work</strong> to handle that click. This means the UI stays responsive, even during long hydration processes, especially helpful on low-end devices. The user can interact, navigate away, or trigger events <strong>without the page feeling stuck.</strong></p>
<p>Now, imagine if the sidebar were also inside a Suspense boundary, just like the blog posts. Both could stream from the server <strong>independently</strong>, right after the initial HTML shell (which might contain the header and navigation).</p>
<p>Once the JavaScript bundle containing the code for both the sidebar and the blog posts arrives, React attempts to hydrate both components. By default, React starts with the <strong>first Suspense boundary it encounters in the tree</strong> — in this case, the sidebar. But now, imagine the user clicks on the blog section before it’s hydrated. Instead of waiting for the sidebar to finish, <strong>React intercepts the event during the capture phase</strong> and <strong>synchronously hydrates the blog section first</strong>, so the interaction works immediately.</p>
<p>🎯 This is <strong>Selective Hydration</strong> in action — solving the third major SSR problem — <strong>You no longer have to hydrate everything before interacting with anything.</strong><br />React begins hydration as soon as possible, but it <strong>prioritizes</strong> what matters most to the user — the part they touch. This creates the <strong>illusion of instant hydration</strong> because interactive components are hydrated first, even if they’re deeper in the component tree.</p>
<h2 id="heading-transition">Transition</h2>
<p>This is an incredible feature going to be released. It lets users resolve the issue of frequent updates on large screens. For example, consider typing in an input field that filters a list of data. You need to store the value of the field in the state so you can filter the data and control the value of that input field. Your code may look something like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Update the input value and search results</span>
setSearchQuery(input);
</code></pre>
<p>Here, whenever the user types a character, we update the input value and use the new value to search the list and show the results. For large-screen updates, this can cause lag on the page while everything renders, making typing or other interactions feel slow and unresponsive. Even if the list is not too long, the list items themselves may be complex and different with every keystroke, and there may be no clear way to optimize their rendering.</p>
<p>Conceptually, this issue involves two different updates that need to happen. The first is urgent, changing the value of the input field and potentially some UI around it. The second is less urgent, showing the search results.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Urgent: Show what was typed</span>
setInputValue(input);

<span class="hljs-comment">// Not urgent: Show the results</span>
setSearchQuery(input);
</code></pre>
<p>The new <code>startTransition</code> API solves this issue by giving you the ability to mark updates as “transitions“:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { startTransition } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-comment">// Urgent: Show what was typed</span>
setInputValue(input);
<span class="hljs-comment">// Mark any state updates inside as transitions</span>
startTransition(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Transition: Show the results</span>
  setSearchQuery(input);
});
</code></pre>
<h2 id="heading-5-new-hooks-in-react-18">5 New Hooks in React 18</h2>
<h3 id="heading-usetransition"><code>useTransition</code></h3>
<p><code>useTransition()</code> is a hook for transition. It returns the transition state and a function to start the transition:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [isPending, startTransition] = useTransition();
</code></pre>
<p>React state updates are classified into two categories:</p>
<ul>
<li><p><strong>Urgent updates</strong>: They reflect direct interaction such as typing, clicking, pressing, dragging, etc.</p>
</li>
<li><p><strong>Transition updates:</strong> They transition the UI from one view to another.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect, useState, useTransition } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> SlowUI = <span class="hljs-function">(<span class="hljs-params">{ value }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    {Array(value)
      .fill(1)
      .map((_, index) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>{value - index} <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      ))}
  <span class="hljs-tag">&lt;/&gt;</span></span>
);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [value, setValue] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> [value2, setValue2] = useState(<span class="hljs-number">100000</span>);
  <span class="hljs-keyword">const</span> [isPending, startTransition] = useTransition();

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">() =&gt;</span> {
    setValue(value + <span class="hljs-number">1</span>);
    startTransition(<span class="hljs-function">() =&gt;</span> setValue2(value2 + <span class="hljs-number">1</span>));
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>{value}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
          <span class="hljs-attr">opacity:</span> <span class="hljs-attr">isPending</span> ? <span class="hljs-attr">0.5</span> <span class="hljs-attr">:</span> <span class="hljs-attr">1</span>,
        }}
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">SlowUI</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{value2}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>The above application is composed of two components (lines 25–32):</p>
<ul>
<li><p><code>button</code> (line 25): It is a simple button. The display number is controlled by <code>value</code> at line 14. Clicking the button increases <code>value</code> (line 19, urgent and fast update) and <code>value2</code> (line 20, transition and slow update).</p>
</li>
<li><p><code>SlowUI</code> (lines 26–32): The component is defined in lines 3–11, which generates <code>100000+</code> <code>span</code> elements controlled by <code>value2</code> at line 15. It takes a longer time to update so many elements. <code>useTransition</code> at line 16 returns the transition state, <code>isPending</code>, and the function to start the transition, <code>startTransition</code>. When <code>startTransition</code> is called on line 20, <code>isPending</code> turns <code>true</code>, and <code>SlowUI</code> is half opaque (light colored) with stale data (line 28). When the transition finishes, <code>isPending</code> turns <code>false</code>, and <code>SlowUI</code> becomes fully opaque (solid colored) with updated data.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=ySqplg27JKY">https://www.youtube.com/watch?v=ySqplg27JKY</a></div>
<p> </p>
<p>Try to remove <code>startTransition</code> line 20 to call <code>setValue2(value2 + 1)</code> directly. You can see that the UI is no longer functional with so many updates happening simultaneously.</p>
<p>The <code>useTransition</code> hook returns <code>isPending</code> and <code>startTransition</code>. If you do not need to show special UI for <code>isPending</code>, remove line 16, and add the following line at the top of the code.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { startTransition } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</code></pre>
<h3 id="heading-usedeferredvalue"><code>useDeferredValue</code></h3>
<p><code>useDeferredValue(value)</code> is a hook that accepts a value and returns a new copy of the value that will defer to more urgent updates. The previous value is kept until urgent updates have been completed. Then, the new value is rendered. This hook is similar to <a target="_blank" href="https://betterprogramming.pub/lodash-create-react-apps-built-in-library-for-debounce-and-throttle-with-hooks-3418087f44d8">using debouncing or throttling to defer updates</a>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useDeferredValue, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> SlowUI = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    {Array(50000)
      .fill(1)
      .map((_, index) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>{100000} <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      ))}
  <span class="hljs-tag">&lt;/&gt;</span></span>
);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [value, setValue] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> deferredValue = useDeferredValue(value);

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">() =&gt;</span> {
    setValue(value + <span class="hljs-number">1</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>{value}<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>DeferredValue: {deferredValue}<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">SlowUI</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>The above application is composed of three components (lines 23–27):</p>
<ul>
<li><p><code>button</code> (line 23): It is a simple button. The display number is controlled by <code>value</code> at line 14. Clicking the button increases <code>value</code> (line 18, urgent and fast update).</p>
</li>
<li><p><code>div</code> (line 24): It displays <code>deferredValue</code>.</p>
</li>
<li><p><code>SlowUI</code> (lines 25–27): The component is defined at lines 3–11, which generates <code>50000</code> fixed-number <code>span</code> elements. Although the component does not have props and visually does not update, it takes a long time to update so many elements.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=lMVG4VR5v9I">https://www.youtube.com/watch?v=lMVG4VR5v9I</a></div>
<p> </p>
<p><code>useDeferredValue</code> can be used in conjunction with <code>startTransition</code> and <code>useTransition</code>.</p>
<h3 id="heading-useid"><code>useId</code></h3>
<p>In a Web application, there are cases that need unique IDs, for example:</p>
<ul>
<li><p><code>&lt;label for="ID"&gt;</code>, where the <code>for</code> attribute must be equal to the <code>id</code> attribute of the related element to bind them together.</p>
</li>
<li><p><code>aria-labelledby</code>, where the <code>aria-labelledby</code> attribute could take multiple IDs.</p>
</li>
</ul>
<p><code>useId()</code> is a hook that generates a unique ID:</p>
<ul>
<li><p>This ID is stable across the server and the client, which avoids hydration mismatches for <a target="_blank" href="https://javascript.plainenglish.io/a-hands-on-guide-for-a-server-side-rendering-react-app-dd1efa3ec0d8">server-side rendering</a>.</p>
</li>
<li><p>This ID is unique for the entire application. In the case of multi-root applications, <code>createRoot</code>/<code>hydrateRoot</code> has an optional prop, <code>identifierPrefix</code>, which can be used to add a prefix to prevent collisions.</p>
</li>
<li><p>This ID can be appended with prefixes and/or suffixes to generate multiple unique ids that are used in a component. It seems trivial. But, <code>useId</code> was evolved from <code>useOpaqueIdentifier</code>, which generates an opaque ID that cannot be operated upon.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useId } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> Comp1 = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> id = useId();
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Comp1 id({id})<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">const</span> Comp2 = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> id = useId();
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Comp2 id({id})<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">id</span>}<span class="hljs-attr">-1</span>`}&gt;</span>Label 1<span class="hljs-tag">&lt;/<span class="hljs-name">label</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">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">id</span>}<span class="hljs-attr">-1</span>`} <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</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">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">id</span>}<span class="hljs-attr">-2</span>`}&gt;</span>Label 2<span class="hljs-tag">&lt;/<span class="hljs-name">label</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">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">id</span>}<span class="hljs-attr">-2</span>`} <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">const</span> Comp3 = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> id = useId();
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Comp3 id({id})<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">aria-labelledby</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">id</span>}<span class="hljs-attr">-a</span> ${<span class="hljs-attr">id</span>}<span class="hljs-attr">-b</span> ${<span class="hljs-attr">id</span>}<span class="hljs-attr">-c</span>`}&gt;</span>I am Comp3<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Comp1</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Comp2</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Comp3</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>The above application is composed of three components (lines 38–40):</p>
<ul>
<li><p><code>Comp1</code>: It is defined in lines 3–6, which generates and displays one id, <code>:r0:</code>.</p>
</li>
<li><p><code>Comp2</code>: It is defined in lines 8–23, which generates one id, <code>:r1:</code>. From this one id, it derives two unique IDs, <code>:r1:-1</code> (for <code>Label 1</code> + the input field) and <code>:r1:-2</code> (for <code>Label 2</code> + the input field).</p>
</li>
<li><p><code>Comp3</code>: It is defined in lines 25–33, which generates and displays one id, <code>:r2:</code>. From his one ID, it derives three unique IDs, <code>:r1:-a</code>, <code>:r1:-b</code>, and <code>:r1:-c</code>, for the <code>aria-labelledby</code> attribute.</p>
</li>
</ul>
<p>Execute the code by <code>npm start</code>. We see the following UI, along with the generated HTML elements in Chrome DevTools.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735729286080/7dc650ab-2469-42f6-b990-74e40bc3eb46.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-usesyncexternalstore"><code>useSyncExternalStore</code></h3>
<p><code>useSyncExternalStore</code> is a hook recommended for reading and subscribing to external sources (stores):</p>
<p>Here is the signature of the hook:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> state = useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot]);
</code></pre>
<p>This method accepts three arguments:</p>
<ul>
<li><p><code>subscribe</code>: It’s a function to register a callback that is called whenever the store changes.</p>
</li>
<li><p><code>getSnapshot</code>: This is a function that returns the current value of the store.</p>
</li>
<li><p><code>getServerSnapshot</code>: It is the function that returns the snapshot used during server rendering. This is an optional parameter.</p>
</li>
</ul>
<p>This method returns the value of the store, <code>state</code>.</p>
<p>We created an example of <code>useSyncExternalStore</code>, which reads the browser window width and displays it on the screen.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useSyncExternalStore } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> width = useSyncExternalStore(
    <span class="hljs-function">(<span class="hljs-params">listener</span>) =&gt;</span> {
      <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'resize'</span>, listener);
      <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">'resize'</span>, listener);
      };
    },
    <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">window</span>.innerWidth
    <span class="hljs-comment">// () =&gt; -1,</span>
  );

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Size: {width}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>The above application calls <code>useSyncExternalStore</code>:</p>
<ul>
<li><p><code>subscribe</code> (lines 5–10): It registers a callback for the window <code>resize</code> event listener.</p>
</li>
<li><p><code>getSnapshot</code> (line 11): It returns the current browser window width.</p>
</li>
<li><p><code>getServerSnapshot</code> (line 12): It is for server rendering, which is not needed here, or simply returns <code>-1</code>.</p>
</li>
</ul>
<p>Execute the code by npm start. The following video shows that the UI displays the browser window width while resizing.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=5gRuqIwXfVw">https://www.youtube.com/watch?v=5gRuqIwXfVw</a></div>
<p> </p>
<h3 id="heading-useinsertioneffect"><code>useInsertionEffect</code></h3>
<p><code>useEffect(didUpdate)</code> accepts a function that contains imperative, possibly effective code, which are mutations, subscriptions, timers, logging, and other side effects. By default, effects run after every completed render, but the invocation can be controlled with an array of second arguments.</p>
<p><code>useLayoutEffect</code> has the same signature as <code>useEffect</code>, but it fires synchronously after all DOM mutations. it’s fired before <code>useEffect</code>. It’s used to read the layout from the DOM and asynchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously before the browser has a chance to paint.</p>
<p><code>useInsertionEffect</code> is introduced in React 18. It has the same signature as <code>useEffect</code>, but it fires synchronously before all DOM mutations. i.e., it is fired before <code>useLayoutEffect</code>. It is used to inject styles into the DOM before reading the layout.</p>
<p>useInsertionEffect is intended for CSS and JS libraries, such as <a target="_blank" href="https://betterprogramming.pub/build-advanced-react-input-fields-using-styled-components-and-storybook-js-a231b9b2438#e765-bf98276875df">styled-components</a>. Since this hook is limited in scope, this hook does not have access to <a target="_blank" href="https://betterprogramming.pub/most-things-you-want-to-know-about-react-refs-29901ebf28c6">refs</a> and cannot schedule updates.</p>
<p>The following example, placed in <code>src/App.js</code>, compares <code>useEffect</code>, <code>useLayoutEffect</code>, and <code>useInsertionEffect</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect, useInsertionEffect, useLayoutEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> Child = <span class="hljs-function">() =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'useEffect child is called'</span>);
  });
  useLayoutEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'useLayoutEffect child is called'</span>);
  });
  useInsertionEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'useInsertionEffect child is called'</span>);
  });
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'useEffect app is called'</span>);
  });
  useLayoutEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'useLayoutEffect app is called'</span>);
  });
  useInsertionEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'useInsertionEffect app is called'</span>);
  });
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Child</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Random Text<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>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>The above application has an <code>App</code> (lines 15–31) and a <code>Child</code> component (lines 3–13). Both of them call <code>useEffect</code>, <code>useLayoutEffect</code>, and <code>useInsertionEffect</code>.</p>
<p>Execute the code by <code>npm start</code>, and we see the displayed text and console output.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735733494100/a0875f39-9564-4cae-9530-b449dfe9e9fa.webp" alt class="image--center mx-auto" /></p>
<p>These effects are called in the following order:</p>
<ul>
<li><p><code>useInsertionEffect</code> child is called.</p>
</li>
<li><p><code>useInsertionEffect</code> app is called.</p>
</li>
<li><p><code>useLayoutEffect</code> child is called.</p>
</li>
<li><p><code>useLayoutEffect</code> app is called.</p>
</li>
<li><p><code>useEffect</code> child is called.</p>
</li>
<li><p><code>useEffect</code> app is called.</p>
</li>
</ul>
<p>This is the expected order.</p>
<p>But why are they called twice?</p>
<p>With the release of React 18, <code>StrictMode</code> gets an additional behavior called strict effects mode. When strict effects are enabled, React intentionally double-invokes effects (<code>mount</code> -&gt; <code>unmount</code> -&gt; <code>mount</code>) for newly mounted components <em>in development mode</em>. Interestingly, <code>useInsertionEffect</code> is not called twice.</p>
<p>Execute <code>npm run build</code>, and <code>serve -s build</code>. We can verify that in <a target="_blank" href="https://javascript.plainenglish.io/a-hands-on-guide-for-creating-a-production-ready-react-app-864ad98e7497">production mode</a>, this app is only mounted once.</p>
<p>Let’s go back to the development mode. After <code>npm start</code>, modify the text to <code>Random Text is changed</code>, and save <code>src/App.js</code>. The additional console log shows how these effects are called upon by changes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735733690604/459258b2-d011-4414-a53e-6d1d4e9de707.webp" alt class="image--center mx-auto" /></p>
<p><code>useInsertionEffect</code> is the hook to be used if we want it to fire before all DOM mutations? However, <code>useInsertionEffect</code> is intended for CSS-in-JS libraries. For normal application developers, <code>useEffect</code> or <code>useLayoutEffect</code> are used more commonly.</p>
<h1 id="heading-react-17">React 17</h1>
<p>Over two years after React 16 was launched, the long-awaited React 17 was released in October 2020. While the update introduced numerous great changes as always, this release is unique because it contains no new developer-facing features. While React 16 added significant features like Hooks and the Context API, React 17 is mostly considered a stepping stone to ease the transition for feature releases.</p>
<h2 id="heading-new-jsx-enhancements">New JSX Enhancements</h2>
<p>A superficial examination of React 17 is sure to leave you unimpressed. What is fascinating is not the new features but the way React is compiled.</p>
<p>To understand these better, let’s examine the compiled code of JSX in a component that uses an older version of React.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735901794716/c5b5d6e4-c782-4678-95d8-8d25fa894cf9.webp" alt class="image--center mx-auto" /></p>
<p>You might notice that the compiled version uses <code>React.createElement</code>, where React dependency should be available in the scope. That’s why you need to import React in the first place in each of the components.</p>
<p>Now let’s take a look at how it works with React 17</p>
<blockquote>
<p>With React 17, you don’t need the React import for JSX.</p>
</blockquote>
<p>I hope that gives you a clue that the compiled version doesn’t require the React import. As you can see in the following image, the React 17 compiler imports a new dependency from <code>react/jsx-runtime</code>, which handles the JSX transformation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735902392684/ce137530-0ba3-479f-9214-3fe871fc4096.webp" alt class="image--center mx-auto" /></p>
<p>So as developers, once you upgrade to React 17, you can remove the React import from your component’s code if it’s only there for JSX.</p>
<p>With the removal of React import, your compiled bundled output will become slightly smaller. I hope it becomes evident since we need to remove the React import from each of the components where the compiler replaces it with a submodule in React, as shown below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {jsx <span class="hljs-keyword">as</span> _jsx} <span class="hljs-keyword">from</span> <span class="hljs-string">'react/jsx-runtime'</span>;
</code></pre>
<h2 id="heading-event-delegation">Event Delegation</h2>
<p>In React (version &lt; React 17), whenever we write any event handlers on elements, it doesn't attach events to the specific DOM nodes, instead, it attaches each handler to the document node. This is called event delegation.</p>
<p>To enable gradual updates, this is the problem if you have multiple React versions on the same page and they all register handlers at the <code>document</code> level.</p>
<p>To fix this, in React 17, all handlers will be attached to the root DOM container defined in your React app where you render the root App component.</p>
<blockquote>
<p>React 17 will no longer attach event handlers at the <code>document</code> level. Instead, it will attach them to the root DOM container into which your React tree is rendered.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735904658359/f8baed00-8294-4573-a078-e33cc067b0cf.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-effect-cleanup-timing">Effect Cleanup Timing</h2>
<p>In React 16, the cleanup function timing in <code>useEffect</code> was synchronous, which meant that when the component was in the unmounting phase, the cleanup function would run first, and then the screen would get updated. If the cleanup logic was computationally expensive or involved asynchronous operations, such as subscribing to an event listener or canceling a network request, it could delay the screen update. This delay was noticeable in heavy apps where multiple components with cleanup logic were being unmounted simultaneously.</p>
<p>Users would perceive a lag in UI responsiveness during transitions or component unmounts. For example, removing a modal or switching views might take longer because the cleanup function execution blocks the screen update.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735905699582/465665e1-9cb6-4a68-b6b5-278ed3bdb51b.webp" alt class="image--center mx-auto" /></p>
<p>React 17 fixes this by making the cleanup function asynchronous. This improves performance.</p>
<blockquote>
<p>According to the React blog, “In React v17, the effect cleanup function always runs asynchronously - for example, if the component is unmounting, the cleanup runs after the screen has been updated.”</p>
</blockquote>
<h1 id="heading-react-160-168">React 16.0 - 16.8</h1>
<p>React 16 had <strong>14 sub-releases</strong> from <strong>16.0.0</strong> to <strong>16.14.0</strong>. Each release introduced improvements, bug fixes, and new features while maintaining backward compatibility.</p>
<h2 id="heading-returns-multiple-elements-from-components-with-fragments">Returns multiple elements from components with fragments</h2>
<p>Splitting UI into multiple reusable small components may lead to the creation of unnecessary DOM elements, like when you need to return multiple elements from a component. React 16 has several options to avoid that:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// React 15: extra wrapper element</span>
<span class="hljs-keyword">const</span> Breakfast = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><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>Coffee<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>Croissant<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>Marmalade<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>
);

<span class="hljs-comment">// React 16.0: array (note that keys are required)</span>
<span class="hljs-keyword">const</span> Breakfast = <span class="hljs-function">() =&gt;</span> [
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"coffee"</span>&gt;</span>Coffee<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>,
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"croissant"</span>&gt;</span>Croissant<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>,
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">"marmalade"</span>&gt;</span>Marmalade<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
];

<span class="hljs-comment">// React 16.2: fragment</span>
<span class="hljs-keyword">const</span> Breakfast = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.Fragment</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Coffee<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>Croissant<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>Marmalade<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.Fragment</span>&gt;</span></span>
);

<span class="hljs-comment">// React 16.2: fragment (short syntax)</span>
<span class="hljs-keyword">const</span> Breakfast = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Coffee<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>Croissant<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>Marmalade<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;/&gt;</span></span>
);

<span class="hljs-comment">// React 16: fragments composition</span>
<span class="hljs-keyword">const</span> Meals = (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Breakfast</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Lunch</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Dinner</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
);
</code></pre>
<p>Note that the short syntax may not be supported by <a target="_blank" href="https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html#support-for-fragment-syntax">the tools you are using</a>.</p>
<h2 id="heading-returning-strings-and-numbers-from-components">Returning strings and numbers from components</h2>
<p>React 16 components can return strings and numbers. This is useful for components that don’t need any markup, like internationalization or formatting:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// React 15</span>
<span class="hljs-keyword">const</span> LocalDate = <span class="hljs-function">(<span class="hljs-params">{ date }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
    {date.toLocaleDateString('de-DE', {
      year: 'numeric',
      month: 'long',
      day: 'numeric'
    })}
  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
);

<span class="hljs-comment">// React 16</span>
<span class="hljs-keyword">const</span> LocalDate = <span class="hljs-function">(<span class="hljs-params">{ date }</span>) =&gt;</span>
  date.toLocaleDateString(<span class="hljs-string">'de-DE'</span>, {
    <span class="hljs-attr">year</span>: <span class="hljs-string">'numeric'</span>,
    <span class="hljs-attr">month</span>: <span class="hljs-string">'long'</span>,
    <span class="hljs-attr">day</span>: <span class="hljs-string">'numeric'</span>
  });
</code></pre>
<h2 id="heading-cancelling-setstate-to-avoid-rendering">Cancelling setState() to avoid rendering</h2>
<p>In React 15, it wasn’t possible to cancel <code>setState()</code> and avoid rendering if your next state was based on the previous state. In React 16, you could return <code>null</code> in <code>setState()</code>’s callback.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// React 16</span>
handleChange = <span class="hljs-function"><span class="hljs-params">event</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> city = event.target.value;
  <span class="hljs-built_in">this</span>.setState(
    <span class="hljs-function"><span class="hljs-params">prevState</span> =&gt;</span> (prevState.city !== city ? { city } : <span class="hljs-literal">null</span>)
  );
};
</code></pre>
<p>In this example calling <code>handleChange()</code> with the same city name as in the state won’t cause a rerender.</p>
<h2 id="heading-avoid-prop-drilling-with-the-official-context-api-163">Avoid prop drilling with the official Context API (16.3)</h2>
<p><a target="_blank" href="https://blog.kentcdodds.com/prop-drilling-bb62e02cb691">Prop drilling</a> is when you pass some data to a deeply nested component using a prop. You have to add this prop to each layer of your React component tree between a component that owns the data and a component that consumes it.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Root</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  state = { <span class="hljs-attr">theme</span>: THEME_DARK };
  handleThemeToggle = <span class="hljs-function"><span class="hljs-params">theme</span> =&gt;</span>
    <span class="hljs-built_in">this</span>.setState(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> ({
      <span class="hljs-attr">theme</span>: theme === THEME_DARK ? THEME_LIGHT : THEME_DARK;
    }));
  render() {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Page</span>
        <span class="hljs-attr">onThemeToggle</span>=<span class="hljs-string">{this.handleThemeToggle}</span>
        {<span class="hljs-attr">...this.state</span>}
        {<span class="hljs-attr">...this.props</span>}
      /&gt;</span></span>
    );
  }
}
<span class="hljs-comment">// Each layer will have to pass theme and theme toggle handler props</span>
&lt;SomeOtherComponent
  onThemeToggle={props.onThemeToggle}
  theme={props.theme}
/&gt;;
<span class="hljs-comment">// Many layers below</span>
<span class="hljs-keyword">const</span> Header = <span class="hljs-function">(<span class="hljs-params">{ theme, onThemeToggle }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{cx(</span>'<span class="hljs-attr">header</span>', `<span class="hljs-attr">header--</span>${<span class="hljs-attr">theme</span>}`)}&gt;</span>
    ...
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onThemeToggle}</span>&gt;</span>Toggle theme<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span></span>
);
</code></pre>
<p>That is a lot of boilerplate code! With the Context API, we can access our theme props anywhere in the component tree.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> ThemeContext = React.createContext(THEME_DARK);
<span class="hljs-comment">// We should wrap our app in this component</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThemeProvider</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  state = { <span class="hljs-attr">theme</span>: THEME_DARK };
  handleThemeToggle = <span class="hljs-function"><span class="hljs-params">theme</span> =&gt;</span>
    <span class="hljs-built_in">this</span>.setState(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> ({
      <span class="hljs-attr">theme</span>: theme === THEME_DARK ? THEME_LIGHT : THEME_DARK
    }));
  render() {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeContext.Provider</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
          <span class="hljs-attr">onThemeToggle:</span> <span class="hljs-attr">this.handleThemeToggle</span>,
          <span class="hljs-attr">theme:</span> <span class="hljs-attr">this.state.theme</span>
        }}
      &gt;</span>
        {this.props.children}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeContext.Provider</span>&gt;</span></span>
    );
  }
}
<span class="hljs-comment">// And then use theme consumer anywhere in the component tree</span>
<span class="hljs-keyword">const</span> Header = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeContext.Consumer</span>&gt;</span>
    {({ theme, onThemeToggle }) =&gt; (
      <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{cx(</span>'<span class="hljs-attr">header</span>', `<span class="hljs-attr">header--</span>${<span class="hljs-attr">theme</span>}`)}&gt;</span>
        ...
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onThemeToggle}</span>&gt;</span>Toggle theme<span class="hljs-tag">&lt;/<span class="hljs-name">button</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">ThemeContext.Consumer</span>&gt;</span></span>
);
</code></pre>
<h2 id="heading-updating-state-based-on-props-with-getderivedstatefromprops">Updating state based on props with getDerivedStateFromProps()</h2>
<p>The <code>getDerivedStateFromProps()</code> lifecycle method is a replacement for <code>componentWillReceiveProps()</code>. It’s useful when you have a prop with a default value for a state property, but you want to reset the state when that prop changes. For example, a modal that has a prop that says if it’s initially open, and a state that says if a modal is open now.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// React 15</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Modal</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  state = {
    <span class="hljs-attr">isOpen</span>: <span class="hljs-built_in">this</span>.props.isOpen
  };
  componentWillReceiveProps(nextProps) {
    <span class="hljs-keyword">if</span> (nextProps.isOpen !== <span class="hljs-built_in">this</span>.state.isOpen) {
      <span class="hljs-built_in">this</span>.setState({
        <span class="hljs-attr">isOpen</span>: nextProps.isOpen
      });
    }
  }
}

<span class="hljs-comment">// React 16.3</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Modal</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  state = {};
  <span class="hljs-keyword">static</span> getDerivedStateFromProps(nextProps, prevState) {
    <span class="hljs-keyword">if</span> (nextProps.isOpen !== prevState.isOpen) {
      <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">isOpen</span>: nextProps.isOpen
      };
    }
  }
}
</code></pre>
<p>The <code>getDerivedStateFromProps()</code> method is called when a component is created and when it receives new props, so you don’t have to convert props to state twice (on initialization and in <code>componentWillReceiveProps()</code>).</p>
<h2 id="heading-rendering-function-components-on-props-change-with-reactmemo-166">Rendering function components on props change with React.memo() (16.6)</h2>
<p><a target="_blank" href="https://reactjs.org/docs/react-api.html#reactmemo">React.memo()</a> does the same for function components as <a target="_blank" href="https://reactjs.org/docs/react-api.html#reactpurecomponent">PureComponent</a> does for class components: only the rerendered component if its props change.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> MyComponent = React.memo(<span class="hljs-function"><span class="hljs-params">props</span> =&gt;</span> {
  <span class="hljs-comment">/* Only rerenders if props change */</span>
});
</code></pre>
<h2 id="heading-other-new-features">Other new features</h2>
<ul>
<li><p><a target="_blank" href="https://reactjs.org/docs/error-boundaries.html">error boundaries</a></p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/docs/portals.html">portals</a></p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/docs/forwarding-refs.html">forwarding refs</a> (16.3)</p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/docs/context.html">the new Context API</a> (16.3)</p>
</li>
<li><p><a target="_blank" href="https://legacy.reactjs.org/docs/react-component.html#getsnapshotbeforeupdate">getSnapshotBeforeUpdate() lifecycle method</a> (16.3)</p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/blog/2018/03/29/react-v-16-3.html">StrictMode component</a> (16.3)</p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/blog/2018/05/23/react-v-16-4.html#pointer-events">pointer events</a> (16.4)</p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html">profiler</a> (16.5)</p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/blog/2018/10/23/react-v-16-6.html#reactlazy-code-splitting-with-suspense">React.lazy</a> (16.6)</p>
</li>
<li><p><a target="_blank" href="https://reactjs.org/blog/2018/10/23/react-v-16-6.html#static-getderivedstatefromerror">static getDerivedStateFromError()</a> (16.6)</p>
</li>
<li><p><a target="_blank" href="https://medium.com/javascript-in-plain-english/understanding-react-16-8-life-cycles-hooks-context-api-lazy-and-suspense-d80760f1b8f2?source=search_post---------0----------------------------">Understanding React 16.8 life cycles, Hooks, Context API, Lazy and Suspense</a> (16.8)</p>
</li>
</ul>
<h1 id="heading-conclusion">Conclusion</h1>
<p>By staying up-to-date with these new methods, developers can leverage the full potential of React.js, writing cleaner and more maintainable code. These advancements reflect React’s commitment to improving developer productivity and delivering high-quality user experiences. Whether you are building a complex web application or a simple component, incorporating these new methods into your workflow can lead to significant improvements in both performance and usability.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://medium.com/gradeup/upgrading-to-react-17-5a5aad38057f">https://medium.com/gradeup/upgrading-to-react-17-5a5aad38057f</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/react-19-released-new-game-changing-features-for-developers-you-must-know-50535f8e05f8">https://levelup.gitconnected.com/react-19-released-new-game-changing-features-for-developers-you-must-know-50535f8e05f8</a></p>
<p><a target="_blank" href="https://blog.bitsrc.io/unleash-the-power-of-server-side-rendering-with-react-server-components-and-next-js-13-10448b803611">https://blog.bitsrc.io/unleash-the-power-of-server-side-rendering-with-react-server-components-and-next-js-13-10448b803611</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/react-19-released-new-game-changing-features-for-developers-you-must-know-50535f8e05f8">https://levelup.gitconnected.com/react-19-released-new-game-changing-features-for-developers-you-must-know-50535f8e05f8</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/what-you-need-to-know-about-react-18-54070f6bc4a1">https://javascript.plainenglish.io/what-you-need-to-know-about-react-18-54070f6bc4a1</a></p>
<p><a target="_blank" href="https://betterprogramming.pub/5-new-hooks-in-react-18-300aa713cefe">https://betterprogramming.pub/5-new-hooks-in-react-18-300aa713cefe</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/react-18-optimizing-performance-with-async-rendering-and-concurrent-mode-60f8c5957f3">https://levelup.gitconnected.com/react-18-optimizing-performance-with-async-rendering-and-concurrent-mode-60f8c5957f3</a></p>
<p><a target="_blank" href="https://blog.bitsrc.io/new-jsx-enhancements-in-react-17-e5f64acbea89">https://blog.bitsrc.io/new-jsx-enhancements-in-react-17-e5f64acbea89</a></p>
<p><a target="_blank" href="https://medium.com/hackernoon/react-16-0-16-3-new-features-for-every-day-use-f397da374acf">https://medium.com/hackernoon/react-16-0-16-3-new-features-for-every-day-use-f397da374acf</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/react-server-components-and-ssr-in-2025-a-game-changing-guide-for-modern-developers-86eba64f9e0a">https://javascript.plainenglish.io/react-server-components-and-ssr-in-2025-a-game-changing-guide-for-modern-developers-86eba64f9e0a</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/cutting-redundant-data-fetches-with-reacts-cache-in-react-19-949ca6c5e364">https://javascript.plainenglish.io/cutting-redundant-data-fetches-with-reacts-cache-in-react-19-949ca6c5e364</a></p>
<p><a target="_blank" href="https://blog.nonstopio.com/react-concurrent-mode-enhancing-app-performance-with-modern-rendering-25c20c69c502">https://blog.nonstopio.com/react-concurrent-mode-enhancing-app-performance-with-modern-rendering-25c20c69c502</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/revolutionize-loading-ux-with-react-18-suspense-streaming-selective-hydration-d8aab5ab77c1">https://javascript.plainenglish.io/revolutionize-loading-ux-with-react-18-suspense-streaming-selective-hydration-d8aab5ab77c1</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/the-hidden-performance-costs-of-react-server-components-34fd9e393096">https://javascript.plainenglish.io/the-hidden-performance-costs-of-react-server-components-34fd9e393096</a></p>
<p><a target="_blank" href="https://medium.com/@sudenurcevik/use-explained-promises-context-suspense-one-render-time-api-in-react-19-7f58cdab23aa">https://medium.com/@sudenurcevik/use-explained-promises-context-suspense-one-render-time-api-in-react-19-7f58cdab23aa</a></p>
<p><a target="_blank" href="https://medium.com/@onix_react/whats-new-in-react-19-2-0-04b9019ceb27">https://medium.com/@onix_react/whats-new-in-react-19-2-0-04b9019ceb27</a></p>
]]></content:encoded></item><item><title><![CDATA[🔥 JavaScript Handbook]]></title><description><![CDATA[When we take our first steps into the wonderful world of programming, we see for ourselves what it does for millions of people. Thanks to programming, the lives of so many people are made easier just by pressing a few keys on their devices. (This is ...]]></description><link>https://blog.tuanhadev.tech/mastering-javascript</link><guid isPermaLink="true">https://blog.tuanhadev.tech/mastering-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[ES6]]></category><category><![CDATA[javascript tips]]></category><category><![CDATA[Advanced JavaScript concepts]]></category><category><![CDATA[JavaScripttricks]]></category><category><![CDATA[Design patterns in JavaScript]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Sun, 08 Dec 2024 11:43:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/mPaKMvE3sHg/upload/dd844cb1fbc4d33e7bbfdd3f1c6824da.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When we take our first steps into the wonderful world of programming, we see for ourselves what it does for millions of people. Thanks to programming, the lives of so many people are made easier just by pressing a few keys on their devices. (This is magic.)</p>
<p>Programming is another kind of superpower, but as Uncle Ben said to his nephew With great power comes great responsibility. In the world of programming, our greatest responsibility is to ensure that the code we write is both easily testable and will remain maintainable over time.</p>
<p>In this blog post, we will discuss some recently added features to the language and some advanced concepts that you could use in your daily coding journey to improve your JavaScript coding.</p>
<h1 id="heading-advanced-javascript-cheatsheet">Advanced JavaScript cheatsheet</h1>
<p>Let’s get down to the root causes that lie at the heart of JavaScript. We will be dealing with some of the more advanced and less well-known sides of JavaScript, such as functions and the <code>this</code> keyword, as often happens in the JavaScript programming language. We will go into the more interesting and complex parts of JavaScript using some practical examples and an in-depth exploration of the topics. Consequently, we will develop a very comprehensive guide designed to be useful to all levels of JS developers.</p>
<h2 id="heading-javascript-under-the-hood">JavaScript Under the Hood</h2>
<p>Every browser has a JavaScript engine. The most popular engine is Google’s V8 engine, which powers Google Chrome and Node.js. Of course, all other browsers have their own JavaScript engines.</p>
<p>A JavaScript engine will always consist of a <strong>Call Stack</strong> and a <strong>Memory Heap</strong> and will run on <strong>one thread</strong>. The JavaScript engine itself runs in several threads (processes) that do different things: compressors, garbage collection, etc.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733562097464/cb98b566-57a8-430e-9099-44bf8e44f981.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-compilation-interpretation-and-just-in-time-compilation">Compilation, Interpretation, and Just-In-Time Compilation</h3>
<p>Computers fundamentally understand machine code, which can be represented as assembly language. Therefore, all software must eventually be converted into a format that a computer can execute immediately. These are three common approaches to this conversion process:</p>
<ul>
<li><p><strong>compilation</strong></p>
</li>
<li><p><strong>interpretation</strong></p>
</li>
<li><p><strong>Just-in-Time compilation</strong></p>
</li>
</ul>
<p><strong>Compilation (Ahead of time compilation)</strong></p>
<p>In this method, all the code is converted to machine language at once and then written to a file in assembly so that the computer can run the software, which can happen even a long time after the file was created.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733563320341/5bb1b6af-2aee-4512-80a4-f9e7908278c5.webp" alt class="image--center mx-auto" /></p>
<p><strong>Interpretation</strong></p>
<p>In this method, <a target="_blank" href="https://en.wikipedia.org/wiki/Interpreter_\(computing\)">the Interpreter</a> goes through the code in an initial pass and then executes it line by line. During the runtime, while running line by line, the code is also compiled into machine language.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733563607832/b08a7862-f16a-4c18-b961-8f522f7b0d9a.webp" alt class="image--center mx-auto" /></p>
<p>In the past, JavaScript was primarily an interpreted language, which led to certain performance limitations. As web developers discovered, interpreting JavaScript line by line made it challenging to implement optimizations effectively. This is partly due to JavaScript’s dynamic nature, where data types can change at runtime. <strong>For example, if a variable is constantly used as a Boolean, an interpreter may still allocate more memory than necessary because it can not make assumptions about the variable’s type</strong>.</p>
<p>Over time, advances in JavaScript engines, such as just-in-time compilation (JIT), have been introduced to address these inefficiencies, resulting in significant performance improvements.</p>
<p><strong>Just-in-time compilation</strong></p>
<p>In this approach, the entire code is translated into machine language in a single step and executed immediately afterward. During the conversion process, no intermediate files are created; instead, the code is directly converted to machine language and executed without delay. This method streamlines the execution process by combining the compilation and execution steps, thereby enhancing the overall efficiency of code processing and execution.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733565628500/5468864e-b0ea-4ce2-ac1f-4aefc3bb9286.webp" alt class="image--center mx-auto" /></p>
<p>Today, JavaScript employs <em>just-in-time (JIT) compilation</em>, which combines the benefits of both interpretation and traditional compilation. This real-time compilation process is faster than interpretation because it eliminates the overhead associated with interpreting code line by line. JIT compilation also offers advantages over ahead-of-time compilation, as it can perform optimizations based on runtime information that would not be available during a traditional compilation process. As a result, code executed using JIT compilation is often faster and more efficient than code executed through either interpretation or ahead-of-time compilation alone.</p>
<h3 id="heading-just-in-time-compilation-in-javascript">Just-in-time compilation in JavaScript</h3>
<p>Now we will talk about how just-in-time compilation is performed in real time in JavaScript.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733566555013/6588af08-7f2d-48fd-a75a-7203f49c26f7.webp" alt class="image--center mx-auto" /></p>
<p><strong>Parsing</strong></p>
<p>In the first step of processing JavaScript code, parsing is performed, which involves reading the code and creating an Abstract Syntax Tree(AST). During this process, the code is broken down into meaningful components according to JavaScript’s syntax, such as significant keywords like const, function, or new. These components are then organized into a structured tree. This stage also includes checking the code for any syntax errors. The resulting AST serves as the basis for converting the JavaScript source code into machine code, which can be executed by the JavaScript engine in subsequent stages.</p>
<p>Say we have a simple primitive variable like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733567016935/f85c1108-1b4f-4582-8eb9-c4159c12f2b6.webp" alt class="image--center mx-auto" /></p>
<p>So this is what the AST looks like for this single line of code. Besides the simple things, such as the name, the value, and the type, there is a lot more data, which is not our concern. Understanding the exact structure of the AST is not crucial, and there is no need to delve into its details. This information is provided merely for general knowledge purposes.</p>
<p>Important note: Despite both being referred to as “trees“, the AST and the DOM Tree are entirely separate concepts and should not be confused due to the shared terminology. The AST is a representation of all the code inside the JavaScript engine.</p>
<p><strong>Compilation and Execution</strong></p>
<p>The subsequent stage is the compilation phase, where the generated AST is converted into machine code. Following this, the machine code is executed immediately, as modern JavaScript engines employ JIT compilation, as previously mentioned. We will soon discuss the execution stage occurring within the call stack. However, the story doesn’t end there. Modern JavaScript engines, such as the V8 engine, employ sophisticated optimization strategies. Initially, they generate an inefficient version of the machine code to enable prompt execution, and then, in the background, the code undergoes an optimization process. After each optimization, the code is recompiled in the optimized version, with the previous code being replaced without disrupting or halting the execution. This process is what makes modern engines so fast.</p>
<p>These processes of compression, compilation, or optimization occur within specialized threads (processes) inside the engine, which are inaccessible to us. This thread operates independently from the main thread where the call stack runs and our code executes.</p>
<p>While different engines may implement this process in various ways, the fundamentals remain the same for modern runtime compilation.</p>
<h3 id="heading-the-javascript-runtime-environment">The JavaScript runtime environment</h3>
<p>Next, we will discuss the JavaScript runtime environment in the browser, which is crucial to understand.</p>
<p>Picture the runtime environment as a container encompassing everything needed to run JavaScript within the browser. At the core of the runtime environment lies the JavaScript engines, which we explored in the previous environment. Without an engine, there is no runtime, and without a runtime, JavaScript cannot function.</p>
<p>However, the engine alone is insufficient. For it to operate correctly within the browser, access to Web APIs is necessary. Web APIs encompass everything related to the DOM, timers, and numerous other APIs that we can access in the browser.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733648644017/ff725b0c-02ed-4706-9a81-5d253f4526b1.webp" alt class="image--center mx-auto" /></p>
<p>For instance, console.log, which we frequently use, is not a part of the language itself but an implementation of an API that JavaScript utilizes. Web APIs are interfaces that offer functionality to the engine in the browser environment, but are not part of the JavaScript language itself. JavaScript accesses these APIs through the global Window object in the browser.</p>
<p>As mentioned earlier, Web APIs are not part of the engine, but they are components of the runtime environment. The runtime environment, as discussed, is a container that holds everything JavaScript needs to function in the browser. The JavaScript runtime also comprises the Callback Queue, a data structure containing all the callback functions that are ready to execute. For example, when attaching an Event Listener to a DOM element like a button, it responds to a click event. We will see this in action later.</p>
<p>The function passed to the event listener is a Callback function. When the event occurs, such as when the button is clicked, the callback function is invoked. What happens is that the callback function is first moved to the Callbacks Queue, and once the Call Stack is empty, the Callback Function transitions to the Call Stack for execution.</p>
<p>This occurs through the so-called Event Loop, which takes Callback Functions from the Callback Queue and places them onto the Call Stack for execution. In this manner, the JavaScript runtime environment implements the Nonblocking Concurrency Model, a non-blocking parallel model. Although JavaScript runs on a single thread, it employs multiple processes using other components in the runtime environment. We will discuss this further later and explain why it makes the entire JavaScript runtime non-blocking.</p>
<p>We have discussed how JavaScript operates in the browser, but it is important to remember that JavaScript can also exist and run outside of browsers, such as in Node.js.</p>
<p>The Node.js runtime environment is quite similar to the browser’s runtime environment. However, since there is no browser, Web APIs are not present, and there is no browser to provide them. Instead, we have C++ Bindings and a Thread Pool. These details are not our primary concern. The essential point to remember is that different JavaScript runtimes exist.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733651526952/0da84319-1645-4d5f-9963-aa5db2bc02b9.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-execution-context">The Execution Context</h3>
<p>So, how is JavaScript code executed? We will now delve deeper into the topic, starting with the Execution Context. While the Execution Context is an abstract concept, it can be defined as <strong>an environment where segments of JavaScript code are executed.</strong> It serves as a container that holds all the necessary information for executing JavaScript code, such as local variables or arguments passed to functions. There will always be only one Execution Context in operation, and the default Execution Context is the Global Execution Context, where the top-level code is executed.</p>
<p>Once the top-level code execution is completed, functions begin to execute. For each function call, a new Execution Context is created, containing all the information required to run that particular function. The same principle applies to methods, as they are merely functions attached to keys within objects.</p>
<p>After all functions have finished executing, the engine waits for the arrival of the Callback Function to run them, such as those linked to Click Events. As a reminder, it is the Event Loop that supplies these Callback Functions from the Callback Queue when the Call Stack is emptied.</p>
<p><strong>The Components of the Execution Context</strong></p>
<p>The first thing we have in the Execution Context is the Variable Environment.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733652812833/0596d7ff-3e6d-4d78-a210-196df04b108c.webp" alt class="image--center mx-auto" /></p>
<p>In this environment, all variables and function declarations are stored. Additionally, a special “arguments“ object is present. As the name suggests, the object contains all the arguments passed to the function currently in the Execution Context, provided the Execution Context belongs to a function. As mentioned earlier, each function has its own Execution Context, so all variables declared by the function will be located in the function’s variable environment. Furthermore, a function can access variables outside of itself due to the Scope Chain. In short, the Scope Chain contains references to all external variables accessible by the function. Lastly, each Execution Context also receives a special variable called the “this” keyword.</p>
<p>In summary, the Execution Context comprises the variable environment, the Scope Chain, and the ‘this‘ Keyword. These components are created during the Creation Phase, which occurs before the execution.</p>
<p>It’s worth mentioning that the Arrow Function does not possess its own <a target="_blank" href="https://blog.logrocket.com/anomalies-in-javascript-arrow-functions/#:~:text=Arrow%20functions%20do%20not%20have%20an%20arguments%20binding">‘arguments‘ object</a> or <a target="_blank" href="https://www.w3schools.com/js/js_arrow_function.asp#:~:text=In%20short,%20with%20arrow%20functions%20there%20are%20no%20binding%20of%20this.">‘this‘ Keyword</a>. Rather, they make use of the ‘arguments‘ object and ‘this‘ keyword from their nearest function or, alternatively, refer to the Global Scope.</p>
<p><strong>The Execution Context in Practice</strong></p>
<p>Let’s look at an example to understand the topic better:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733654834531/68b215a2-65a4-438d-908d-564c28389c71.webp" alt class="image--center mx-auto" /></p>
<p>Initially, a Global Execution Context is created for the Top-level code, which is any code not contained within a function. So, at first, only this code is executed. This makes sense because functions only run when they are executed or triggered. In this example, the ‘first‘ variable is in the TOP Level code, so it’s executed in the Global Execution Context. It’s known that the value of ‘<strong><em>first</em></strong>’ is 5, ‘<strong><em>second</em></strong>’ and ‘<strong><em>third</em></strong>’ are functions, and the value of ‘<strong><em>fourth</em></strong>’ is still unknown.</p>
<p>In line 14, to get the value of ‘<strong><em>fourth</em></strong>’, the ‘<strong><em>second</em></strong>’ function is activated, and its Execution Context is created. Here, the value of ‘<strong><em>a</em></strong>’ is known to be 1, but the value of ‘<strong><em>b</em></strong>’ is still unknown, as it must be obtained from the ‘<strong><em>third</em></strong>’ function. So, the ‘<strong><em>third</em></strong>’ function runs, and its Execution Context is created with the value of ‘<strong><em>c</em></strong>’ being 3 and its ‘arguments’ object containing 1 and 2, which were passed when the function was executed. Now, ‘<strong><em>third</em></strong>’ returns 6 (1 + 2 + 3), we return to the Execution Context of ‘<strong><em>second</em></strong>’, and the value of ‘<strong><em>b</em></strong>’ is now 6. Finally, ‘<strong><em>second</em></strong>’ returns 7 (6 + 1), and the value of ‘<strong><em>fourth</em></strong>’ is determined as 7 in the Global Execution Context.</p>
<p>In this small and seemingly simple example, we observed a rather complex process. This raises the question of how the JavaScript engine knows when to execute functions and which Execution Context should be the current one, especially in more intricate code examples. This is where the Call Stack comes into play.</p>
<h3 id="heading-the-call-stack">The Call Stack</h3>
<p>As previously mentioned, the JavaScript runtime includes the JavaScript engine, which itself comprises the Memory Heap and the Call Stack. So, what exactly is the Call Stack?</p>
<p>The Call Stack is where Execution Contexts are stacked on top of one another to keep track of the program’s execution. At any given moment, the topmost Execution Context is the one being executed, following the Last-In-First-Out (LIFO) method.</p>
<p>Referring back to the previous example, the Global Execution Context initially occupies the Call Stack. When the ‘<strong><em>second</em></strong>’ function is called, it moves to the top of the Call Stack, followed by the ‘<strong><em>third</em></strong>’ function when it is called. Once the ‘<strong><em>third</em></strong>’ function finishes and returns a value, it is removed from the Call Stack. Similarly, when the ‘<strong><em>second</em></strong>’ function concludes, it is also removed, leaving the Global Execution Context with all the values it was waiting for.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733656201409/48a0db2e-80a4-499e-8633-a4bd3be34c65.webp" alt class="image--center mx-auto" /></p>
<p>It’s crucial to understand that while any Execution Context is running and positioned at the top of the Call Stack, all other Execution Contexts are suspended and waiting for the current one to be completed. This occurs because JavaScript operates on a single thread, requiring operations to be performed sequentially rather than in parallel. The Call Stack is an essential component of the JavaScript engine itself and not a separate part of the runtime environment.</p>
<p>In this way, the Call Stack maintains the execution order of the Execution Context, ensuring that the sequence of execution is always preserved.</p>
<h2 id="heading-why-is-javascript-single-threaded-and-why-thats-a-good-thing">Why is JavaScript Single-Threaded (And Why That’s a Good Thing)</h2>
<p>Imagine you are in a restaurant, where there is only one chef, and this chef handles everything —taking orders, cooking meals, plating dishes, and even cleaning up. Sounds a bit slow, right? But here is a twist: this chef is a master of efficiency. He does one thing at a time and never drops a ball. Now imagine this chef is your JavaScript engine.</p>
<p>This is basically how JavaScript works: it runs in a single-threaded environment. But why was JavaScript designed this way? What does “single-threaded“ even mean? And if JavaScript can only do one thing at a time, how does it still handle animations, API calls, and user inputs so smoothly?</p>
<h3 id="heading-what-does-single-threaded-mean">What Does “Single-Threaded“ Mean?</h3>
<p>Let’s break this down first.</p>
<p>A thread is like a line of execution — it’s a path your computer uses to run code. A single-threaded language means it runs one command at a time, in order, from top to bottom.</p>
<p>Here’s a simple analogy:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">"First"</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Second"</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Third"</span>);
</code></pre>
<p>Output:</p>
<pre><code class="lang-typescript">First
Second
Third
</code></pre>
<p>The output is always in order. JavaScript reads each line, executes it, and moves to the next. It doesn’t skip or jump ahead unless you tell it to.</p>
<p>In contrast, a multi-threaded language like Java or C++ can run multiple pieces of code simultaneously using threads. This can be faster but also more complex — and dangerous if not handled properly.</p>
<h3 id="heading-why-javascript-was-designed-to-be-single-threaded">Why JavaScript Was Designed to be Single-Threaded?</h3>
<p><em>Let’s rewind to 1995 — the year JavaScript was created by Brendan Eich at Netscape.</em></p>
<p><strong><em>At that time, the internet was very different. Websites are mostly static. JavaScript was created to make pages more interactive. Think form validations, button clicks, pop-ups — basic stuff.</em></strong></p>
<p>Now here’s the key part: browsers already had a complex job. They had to render HTML, apply CSS, and keep the page layout consistent. Adding a multi-threaded scripting engine to this would have been throwing gasoline into a fire.</p>
<p>So, they made a trade-off:</p>
<blockquote>
<p><em>“Let’s keep it simple. One thread. One call stack. One thing at a time.”</em></p>
</blockquote>
<p>This choice:</p>
<ul>
<li><p>Made JavaScript easier to implement inside browsers</p>
</li>
<li><p>Prevented a whole class of bugs that come with shared memory (more on this later)</p>
</li>
<li><p>Made code easier to read and reason about</p>
</li>
</ul>
<p>And believe it or not, this “limitation” became one of JavaScript’s greatest strengths.</p>
<h3 id="heading-the-callstack-javascripts-brain">The CallStack: JavaScript’s Brain</h3>
<p>To understand single-threaded behavior, you need to know about the <strong>Call Stack</strong>.</p>
<p>The Call Stack is a data structure that keeps track of function calls in your code. Every time a function is called, it’s added (or “pushed”) to the stack. When it finishes, it’s removed (or “popped”).</p>
<p>Let’s see an example:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greet</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello"</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">start</span>(<span class="hljs-params"></span>) </span>{
  greet();
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Welcome!"</span>);
}
start();
</code></pre>
<p>Here’s what happens:</p>
<ol>
<li><p><code>start()</code> is added to the stack</p>
</li>
<li><p>Inside <code>start()</code>, <code>greet()</code> is called — added to the stack</p>
</li>
<li><p><code>console.log("Hello")</code> is executed — printed</p>
</li>
<li><p><code>greet()</code> finishes — removed from stack</p>
</li>
<li><p><code>console.log("Welcome!")</code> is executed</p>
</li>
<li><p><code>start()</code> finishes — removed from stack</p>
</li>
</ol>
<p>Everything happens in a strict order — <strong>synchronously</strong>. That’s the single-threaded way.</p>
<p>Here’s the magic twist. JavaScript <em>feels</em> asynchronous, right? You click buttons, send requests, and see updates — all without freezing the page.</p>
<p>How?</p>
<p>This is where the <strong>Event Loop</strong> comes in.</p>
<h3 id="heading-event-loop">Event Loop</h3>
<p>Oh, boy, the event loop. It’s one of those things that every JavaScript developer has to deal with in one way or another, but it can be a bit confusing to understand at first. I am a visual learner, so I thought I would try to help you by explaining it in a visual way through low-res gifs because it’s 2024 and gifs are somehow still pixelated and blurry.</p>
<p>But first, what is the event loop, and why should you care?</p>
<p>JavaScript is single-threaded: only one task can run at a time. Usually, that is no big deal, but now imagine you are running a task that takes 30 seconds. During that task, we wait for 30 seconds before anything else happens (JavaScript runs on the browser’s main thread by default, so the Ui is stuck). It’s 2024, no one wants slow, unresponsive websites.</p>
<p>Luckily, the browser gives us some features that JavaScript itself doesn’t provide: a Web API. This includes a DOM API, setTimeout, HTTP requests, and so on. This can help us create some sync and non-blocking behavior.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=eiC58R16hb8">https://www.youtube.com/watch?v=eiC58R16hb8</a></div>
<p> </p>
<p>For more details, refer to <a target="_blank" href="https://www.lydiahallie.com/blog/event-loop">this article</a>.</p>
<h3 id="heading-why-single-threaded-is-safer">Why Single-Threaded is Safer</h3>
<p>Multi-threaded programming brings its own problems, especially race conditions and deadlocks.</p>
<p>Imagine two threads trying to change the same variable at the same time.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Pseudo Java code</span>
thread1: userBalance += <span class="hljs-number">100</span>;
thread2: userBalance -= <span class="hljs-number">50</span>;
</code></pre>
<p>If both threads access <code>userBalance</code> at the same time, who wins? You don’t know — it depends on timing.</p>
<p>In JavaScript, it isn’t a problem. Because everything runs in sequence, one after another.</p>
<p>This predictability is why JavaScript avoids many of the headaches that come with threading.</p>
<h3 id="heading-how-nodejs-uses-this-model-for-servers">How Node.js Uses This Model For Servers?</h3>
<p>When Node.js came out in 2009, people laughed. “A single-threaded server? That’ll never scale.”</p>
<p>They were wrong.</p>
<p>Node.js used the same event-driven, non-blocking model from the browser and applied it to server-side code.</p>
<p>Instead of using one thread per request (like in Java or PHP), Node.js uses one thread for all requests, with the help of the event loop.</p>
<p>When a request comes in:</p>
<ul>
<li><p>It does the work it can</p>
</li>
<li><p>If something takes time (like file access), it passes it to the background</p>
</li>
<li><p>Continues with the next request</p>
</li>
</ul>
<p>This makes Node.js extremely efficient for I/O-heavy applications like APIs or real-time apps (chat, games).</p>
<h2 id="heading-javascript-visualized-prototypal-inheritance">JavaScript Visualized: Prototypal Inheritance</h2>
<p>Ever wondered why we can use built-in methods such as <code>.length</code>, <code>.split()</code>, <code>.join()</code> on our strings, arrays, or objects? We never explicitly specified them. Where do they come from? Don’t say “It’s JavaScript lol no one knows, it’s magic“, it’s actually because of something called prototypal inheritance. It’s pretty awesome, and you use it more often than you realize.</p>
<p>You often have to create many objects of the same type. Say we have a website where people can browse dogs.</p>
<p>For every dog, we need objects that represent that dog! Instead of writing a new object each time, we will use a constructor function (I know what you are thinking, we will cover ES6 classes later on) from which we can create Dog instances using the new keyword(this post isn’t really about explaining constructor functions, though, so I won't talk much about that)</p>
<p>Every dog has a name, a breed, a color, and a function to bark.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732347764132/05e4b7ef-23ae-4cb0-8ff3-fa5d3ffbd2a9.png" alt class="image--center mx-auto" /></p>
<p>Check out <a target="_blank" href="https://dev.to/lydiahallie/javascript-visualized-prototypal-inheritance-47co">this article</a> to explore amazing things about prototypal inheritance.</p>
<h3 id="heading-difference-between-prototype-and-proto">Difference between prototype and __<strong>proto</strong>__</h3>
<p>The <code>prototype</code> property is an attribute associated with a constructor function in JavaScript. Constructor functions are used to create objects in JavaScript. When you define a constructor function, you can also attach properties and methods to its <code>prototype</code> property. These properties and methods then become accessible to all instances of objects created from that constructor. Thus, the <code>prototype</code> property serves as the <strong>common repository</strong> for methods and properties that are shared among instances.</p>
<p>Consider the following code snippet:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Constructor function</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Person</span>(<span class="hljs-params">name</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name;
}

<span class="hljs-comment">// Adding a method to the prototype</span>
Person.prototype.sayHello = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, my name is <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>.`</span>);
};

<span class="hljs-comment">// Creating instances</span>
<span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Haider Wain"</span>);
<span class="hljs-keyword">const</span> person2 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Omer Asif"</span>);

<span class="hljs-comment">// Calling the shared method</span>
person1.sayHello();  <span class="hljs-comment">// Output: Hello, my name is Haider Wain.</span>
person2.sayHello();  <span class="hljs-comment">// Output: Hello, my name is Omer Asif.</span>
</code></pre>
<p>In this example, we have a constructor function named <code>Person</code>. By extending the <code>Person.prototype</code> with a method like <code>sayHello</code>, we are adding this method to the prototype chain of all <code>Person</code> instances. This allows each instance of <code>Person</code> to access and utilize the shared method. Instead, each instance has its own copy of the method.</p>
<p>On the other hand, the <code>__proto__</code> property, often pronounced as "dunder proto," exists in every JavaScript object. In JavaScript, everything, except primitive types, can be treated as an object. Each of these objects has a prototype, which serves as a reference to another object. The <code>__proto__</code> property is simply a reference to this prototype object. The prototype object is used as a fallback source for properties and methods when the original object doesn’t possess them. By default, when you create an object, its prototype is set to <code>Object.prototype</code>.</p>
<p>When you attempt to access a property or method on an object, JavaScript follows a lookup process to find it. This process involves two main steps:</p>
<ol>
<li><p><strong>Object’s Own Properties</strong>: JavaScript first checks if the object itself directly possesses the desired property or method. If the property is found within the object, it’s accessed and used directly.</p>
</li>
<li><p><strong>Prototype Chain Lookup:</strong> If the property is not found in the object itself, JavaScript looks at the object’s prototype (referenced by the <code>__proto__</code> property) and searches for the property there. This process continues recursively up the prototype chain until the property is found or until the lookup reaches the <code>Object.prototype</code>.</p>
</li>
</ol>
<p>If the property is not found even in the <code>Object.prototype</code>, JavaScript returns <code>undefined</code>, indicating that the property does not exist.</p>
<h2 id="heading-javascript-visualized-promise-and-asyncawait">JavaScript Visualized: Promise and Async/Await</h2>
<p>Have you ever had to deal with JS code that just… didn’t run the way you expected it to? Maybe it seemed like functions got executed at random, unpredictable times, or the execution got delayed. There is a chance you were dealing with a cool new feature that ES6 introduced: Promises!</p>
<p>My curiosity from many years ago has paid off, and my sleepless nights have once given me the time to make some animations. Time to talk about Promises: why would you use them? How do they work “under the hood“, and how can we write them in the most modern ways?</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=Xs1EMmBLpn4">https://www.youtube.com/watch?v=Xs1EMmBLpn4</a></div>
<p> </p>
<p>All of those questions will be answered in <a target="_blank" href="https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke">this article</a>.</p>
<h2 id="heading-stop-writing-asyncawait-like-this-heres-what-senior-developers-do">Stop Writing Async/Await Like This — Here’s What Senior Developers DO</h2>
<p>Do you know what’s interesting about <code>async/await</code> JavaScript? It feels like one of those "finally!" features when you first discover it. Clean syntax, readable code, and it just makes sense.</p>
<p>But here’s the thing — the more I work with async code and chat with other developers, the more I notice we all trip over the same sneaky issues, like those little details that only become obvious once you’re working with it.</p>
<p>I spend a lot of time reviewing code and keep seeing these patterns pop up. Not because anyone’s writing bad code, but because async programming has some genuinely tricky parts. Let’s explore them together and look at what works in real-world applications.</p>
<p>Ready to dive in? Let’s start with some patterns that might surprise you…</p>
<h3 id="heading-the-evolution-of-asynchronous-javascript">The evolution of Asynchronous JavaScript</h3>
<p>Remember the old days of callback hell? We’ve come a long way:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756023312344/ce474e9b-ac63-4735-8a88-99cdde758cc9.webp" alt class="image--center mx-auto" /></p>
<blockquote>
<p>But with great power comes great responsibility.</p>
</blockquote>
<p>Let’s look at what separates junior code from senior code.</p>
<h3 id="heading-the-three-deadly-sins-of-asyncawait">The Three Deadly Sins of async/await</h3>
<ol>
<li><strong>The Sequential Waterfall</strong></li>
</ol>
<p>Here’s what I often see in code reviews: perfectly good async operations lined up like soldiers, waiting their turn while they could march together.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 🚫 Don't do this</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loadDashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> fetchUser();
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> fetchPosts();
  <span class="hljs-keyword">const</span> notifications = <span class="hljs-keyword">await</span> fetchNotifications();
}
</code></pre>
<p>If each request takes 200ms, you are looking at a 600ms wait. Your users deserve better.</p>
<p>Instead, senior developers know when operations can run in parallel — and more importantly, when they shouldn’t:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ✅ Do this for independent operations</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loadDashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [user, posts, notifications] = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all([
    fetchUser(),
    fetchPosts(),
    fetchNotifications()
  ]);
}
</code></pre>
<p>Now we are taking. Same results, one-third of the time. However, this is crucial; parallelism isn’t always the answer. You ned to watch out for:</p>
<ul>
<li><p>Dependencies: If one operation needs data from another, they must be sequential.</p>
</li>
<li><p>Race conditions: Parallel operations modifying shared resources can cause subtle bugs.</p>
</li>
<li><p>Resource Limits: Too many parallel requests can overwhelm servers or browsers.</p>
</li>
</ul>
<p>Here’s a real-world example, while parallel operations would be dangerous:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 🚫 Dangerous parallel execution</span>
<span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all([
  updateUserProfile(userId, { name: <span class="hljs-string">'New Name'</span> }),
  updateUserProfile(userId, { email: <span class="hljs-string">'new@email.com'</span> })
]);


<span class="hljs-comment">// ✅ Safe sequential execution</span>
<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> updateUserProfile(userId, { name: <span class="hljs-string">'New Name'</span> });
<span class="hljs-keyword">await</span> updateUserProfile(userId, { email: <span class="hljs-string">'new@email.com'</span> });
</code></pre>
<p>In the parallel version, you could end up with inconsistent data due to race conditions. Always consider the implications of concurrent operations.</p>
<p><strong>2. The Silent Failure: Finding the Right Balance</strong></p>
<p>This is the pattern I see often — The Sync equivalent of sweeping dust under the rug:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 🚫 The silent killer</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/data'</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> response.json();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(error);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;  <span class="hljs-comment">// 🚨 Problems hide here</span>
  }
}
</code></pre>
<p>Junior developers often handle errors this way because this makes the code “work”. But it’s creating a time bomb. When something goes wrong, you won’t know.</p>
<ul>
<li><p>Was it a network error?</p>
</li>
<li><p>Was the server down?</p>
</li>
<li><p>Was the response not valid JSON?</p>
</li>
<li><p>Did the user lose connection?</p>
</li>
</ul>
<p>Now, here is a nuanced part that many tutorials miss: returning null or a fallback value isn’t always wrong.</p>
<p>For non-critical UI elements like notifications, activity feeds, or recommendation panels, gracefully degrading with a fallback can actually improve user experience. The key is being intentional about it:</p>
<p>Senior developers make errors meaningful and contextual:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ✅ Clear error handling with context</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params">options = {}</span>) </span>{
  <span class="hljs-keyword">const</span> { isCritical = <span class="hljs-literal">true</span> } = options;

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/data'</span>);
    <span class="hljs-keyword">if</span> (!response.ok) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP error! status: <span class="hljs-subst">${response.status}</span>`</span>);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> response.json();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-comment">// Log all errors for monitoring</span>
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Data fetch failed:'</span>, error);

    <span class="hljs-keyword">if</span> (isCritical) {
      <span class="hljs-comment">// Critical data - propagate error for handling at a higher level</span>
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ApiError(<span class="hljs-string">'Failed to fetch critical data'</span>, { cause: error });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-comment">// Non-critical data - return fallback value</span>
      <span class="hljs-keyword">return</span> { <span class="hljs-keyword">type</span>: <span class="hljs-string">'fallback'</span>, data: [] };
    }
  }
}

<span class="hljs-comment">// Usage examples:</span>

<span class="hljs-comment">// Critical data (will throw on error)</span>
<span class="hljs-keyword">const</span> userData = <span class="hljs-keyword">await</span> fetchData({ isCritical: <span class="hljs-literal">true</span> });

<span class="hljs-comment">// Non-critical notifications (graceful fallback)</span>
<span class="hljs-keyword">const</span> notifications = <span class="hljs-keyword">await</span> fetchData({ isCritical: <span class="hljs-literal">false</span> });
</code></pre>
<p>This approach gives you the best of both worlds: proper error handling for critical operations and graceful degradation for non-critical features.</p>
<ol start="3">
<li><strong>The Memory Leak Monster and Modern Clean Up</strong></li>
</ol>
<p>This one is subtle but deadly, especially in long-running applications. Let’s look at a common polling implementation:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 🚫 Memory leak in disguise</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">startPolling</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">setInterval</span>(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchData();
    updateUI(data);
  }, <span class="hljs-number">5000</span>);
}
</code></pre>
<p>Looks innocent, right? Wrong. This code:</p>
<ul>
<li><p>Never stop polling, even if the component is destroyed</p>
</li>
<li><p>It can cause multiple concurrent requests if fetchData is slow.</p>
</li>
<li><p>Might update a UI that no longer exists</p>
</li>
</ul>
<p>Modern JavaScript gives us better tools for handling async cleanup. Here’s how senior developers approach it:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> PollingManager {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">options = {}</span>) {
    <span class="hljs-built_in">this</span>.controller = <span class="hljs-keyword">new</span> AbortController();
    <span class="hljs-built_in">this</span>.interval = options.interval || <span class="hljs-number">5000</span>;
  }

  <span class="hljs-keyword">async</span> start() {
    <span class="hljs-keyword">while</span> (!<span class="hljs-built_in">this</span>.controller.signal.aborted) {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/data'</span>, {
          signal: <span class="hljs-built_in">this</span>.controller.signal
        });

        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
        updateUI(data);

        <span class="hljs-comment">// Wait for next interval</span>
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> 
          <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-built_in">this</span>.interval)
        );
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">if</span> (error.name === <span class="hljs-string">'AbortError'</span>) {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Polling stopped'</span>);
          <span class="hljs-keyword">return</span>;
        }
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Polling error:'</span>, error);
      }
    }
  }

  stop() {
    <span class="hljs-built_in">this</span>.controller.abort();
  }
}

<span class="hljs-comment">// Usage in React</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DataComponent</span>(<span class="hljs-params"></span>) </span>{
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> poller = <span class="hljs-keyword">new</span> PollingManager({ interval: <span class="hljs-number">5000</span> });
    poller.start();

    <span class="hljs-comment">// Cleanup when component unmounts</span>
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> poller.stop();
  }, []);

  <span class="hljs-keyword">return</span> &lt;div&gt;Data: {<span class="hljs-comment">/* ... */</span>}&lt;/div&gt;;
}
</code></pre>
<p>This modern approach using AbortController provides several benefits:</p>
<ul>
<li><p>Proper cleanup of in-flight requests</p>
</li>
<li><p>Immediate cancellation if needed</p>
</li>
<li><p>Better memory management</p>
</li>
<li><p>Clear life cycle management</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756028579198/4e36f0b6-f6dc-4811-8713-d6f1d00d0842.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-5-asyncawait-patterns">5 Async/Await Patterns</h3>
<ol>
<li><strong>The Error Boundary Pattern (Graceful Failure Recovery)</strong></li>
</ol>
<p><strong>The Secret:</strong> Professional JavaScript developers use strategic error boundaries in async functions to create resilient applications where partial failures don’t crash the entire user experience.</p>
<p><strong>❌ Amateur Approach: All-or-Nothing Failures</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processUserData</span>(<span class="hljs-params">userId</span>) </span>{
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> fetchUser(userId);
  <span class="hljs-keyword">const</span> preferences = <span class="hljs-keyword">await</span> fetchPreferences(userId);
  <span class="hljs-keyword">const</span> recommendations = <span class="hljs-keyword">await</span> generateRecommendations(user, preferences);

  <span class="hljs-keyword">return</span> { user, preferences, recommendations };
  <span class="hljs-comment">// If ANY step fails, the entire function fails</span>
}
</code></pre>
<p><strong>✅ Professional Technique: Graceful Degradation</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processUserData</span>(<span class="hljs-params">userId</span>) </span>{
  <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.allSettled([
    fetchUser(userId),
    fetchPreferences(userId).catch(<span class="hljs-function">() =&gt;</span> getDefaultPreferences()),
  ]);

  <span class="hljs-keyword">const</span> [userResult, preferencesResult] = results;

  <span class="hljs-keyword">if</span> (userResult.status === <span class="hljs-string">'rejected'</span>) {
    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Only critical failures stop execution
     * User data is required, so we throw immediately
     * ================================================ */</span>
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'User data required but unavailable'</span>);
  }

  <span class="hljs-keyword">const</span> user = userResult.value;
  <span class="hljs-keyword">const</span> preferences = preferencesResult.value;

  <span class="hljs-comment">/* ================================================
   * 🎯 SECRET: Optional features fail gracefully
   * Recommendations enhance UX but aren't critical
   * ================================================ */</span>
  <span class="hljs-keyword">const</span> recommendations = <span class="hljs-keyword">await</span> generateRecommendations(user, preferences)
    .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
      <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">'Recommendations unavailable:'</span>, error.message);
      <span class="hljs-keyword">return</span> []; <span class="hljs-comment">// Return empty array instead of crashing</span>
    });

  <span class="hljs-keyword">return</span> { user, preferences, recommendations };
}
</code></pre>
<p><strong>Why this works:</strong> Promise.allSettled allows some operations to fail while others succeed. Critical data throws errors, and optional data degrades gracefully. This creates applications that work even when external services have issues.</p>
<p><strong>Advanced Implementation:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> DataService {
  <span class="hljs-keyword">async</span> processUserWithFallbacks(userId) {
    <span class="hljs-keyword">const</span> strategies = [
      <span class="hljs-comment">/* ================================================
       * 🎯 ADVANCED: Multiple fallback strategies
       * Primary API → Cache → Default values
       * ================================================ */</span>
      () =&gt; <span class="hljs-built_in">this</span>.fetchFromPrimaryAPI(userId),
      <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">this</span>.fetchFromCache(userId),
      <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">this</span>.generateDefaultUser(userId)
    ];

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> strategy <span class="hljs-keyword">of</span> strategies) {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> strategy();
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isValidUserData(result)) {
          <span class="hljs-keyword">return</span> result;
        }
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">'Strategy failed, trying next:'</span>, error.message);
      }
    }

    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'All user data strategies exhausted'</span>);
  }
}
</code></pre>
<p><strong>Real-world applications:</strong></p>
<ul>
<li><p>Dashboard loading with partial data display</p>
</li>
<li><p>E-commerce checkout with optional features</p>
</li>
<li><p>Social media feeds with graceful content loading</p>
</li>
<li><p>Banking apps with fallback transaction methods</p>
</li>
</ul>
<p><strong>Pro tip:</strong> Use meaningful error messages that help with debugging: “User data required but unavailable” is better than “Request failed”.</p>
<ol start="2">
<li><strong><mark>The Async Queue Pattern (Controlled Concurrency)</mark></strong></li>
</ol>
<p><strong>The Secret:</strong> Professional developers never let async operations run wild. They use concurrency control to prevent server overload while maintaining optimal performance.</p>
<p><strong>❌ Amateur Approach: Parallel Chaos</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processFiles</span>(<span class="hljs-params">files</span>) </span>{
  <span class="hljs-comment">// This might overwhelm the server with 100 concurrent requests</span>
  <span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(
    files.map(<span class="hljs-function"><span class="hljs-params">file</span> =&gt;</span> uploadFile(file))
  );
  <span class="hljs-keyword">return</span> results;
}
</code></pre>
<p><strong>✅ Professional Technique: Controlled Batching</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processFiles</span>(<span class="hljs-params">files, concurrency = 3</span>) </span>{
  <span class="hljs-keyword">const</span> results = [];
  <span class="hljs-keyword">const</span> queue = [...files];

  <span class="hljs-keyword">while</span> (queue.length &gt; <span class="hljs-number">0</span>) {
    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Process in controlled batches
     * Prevents server overload and rate limiting
     * ================================================ */</span>
    <span class="hljs-keyword">const</span> batch = queue.splice(<span class="hljs-number">0</span>, concurrency);

    <span class="hljs-keyword">const</span> batchResults = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(
      batch.map(<span class="hljs-keyword">async</span> (file, index) =&gt; {
        <span class="hljs-keyword">try</span> {
          <span class="hljs-comment">/* ================================================
           * 🎯 SECRET: Individual error handling per file
           * One failed upload doesn't stop the entire batch
           * ================================================ */</span>
          <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> uploadFile(file);
          <span class="hljs-keyword">return</span> { success: <span class="hljs-literal">true</span>, file: file.name, data: result };
        } <span class="hljs-keyword">catch</span> (error) {
          <span class="hljs-keyword">return</span> { 
            success: <span class="hljs-literal">false</span>, 
            file: file.name, 
            error: error.message 
          };
        }
      })
    );

    results.push(...batchResults);

    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Progress reporting for UX
     * Users see incremental progress, not just loading
     * ================================================ */</span>
    <span class="hljs-keyword">const</span> completed = results.length;
    <span class="hljs-keyword">const</span> total = files.length;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Progress: <span class="hljs-subst">${completed}</span>/<span class="hljs-subst">${total}</span> files processed`</span>);
  }

  <span class="hljs-keyword">return</span> results;
}
</code></pre>
<p><strong>Why this works:</strong> Controlled concurrency respects server limits while still providing parallelism. Most APIs have rate limits — this pattern respects them while maximizing throughput.</p>
<p><strong>Advanced Implementation:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> AsyncQueue {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">concurrency = 3</span>) {
    <span class="hljs-built_in">this</span>.concurrency = concurrency;
    <span class="hljs-built_in">this</span>.running = <span class="hljs-number">0</span>;
    <span class="hljs-built_in">this</span>.queue = [];
  }

  <span class="hljs-keyword">async</span> add(asyncFunction) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
      <span class="hljs-comment">/* ================================================
       * 🎯 ADVANCED: Dynamic queue management
       * Automatically manages execution without blocking
       * ================================================ */</span>
      <span class="hljs-built_in">this</span>.queue.push({
        fn: asyncFunction,
        resolve,
        reject
      });

      <span class="hljs-built_in">this</span>.process();
    });
  }

  <span class="hljs-keyword">async</span> process() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.running &gt;= <span class="hljs-built_in">this</span>.concurrency || <span class="hljs-built_in">this</span>.queue.length === <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-built_in">this</span>.running++;
    <span class="hljs-keyword">const</span> { fn, resolve, reject } = <span class="hljs-built_in">this</span>.queue.shift();

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> fn();
      resolve(result);
    } <span class="hljs-keyword">catch</span> (error) {
      reject(error);
    } <span class="hljs-keyword">finally</span> {
      <span class="hljs-built_in">this</span>.running--;
      <span class="hljs-built_in">this</span>.process(); <span class="hljs-comment">// Process next item</span>
    }
  }
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">const</span> queue = <span class="hljs-keyword">new</span> AsyncQueue(<span class="hljs-number">3</span>);
<span class="hljs-keyword">const</span> uploadPromises = files.map(<span class="hljs-function"><span class="hljs-params">file</span> =&gt;</span> 
  queue.add(<span class="hljs-function">() =&gt;</span> uploadFile(file))
);
<span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(uploadPromises);
</code></pre>
<p><strong>Real-world applications:</strong></p>
<ul>
<li><p>Image processing and uploads</p>
</li>
<li><p>API data synchronization</p>
</li>
<li><p>Batch email sending</p>
</li>
<li><p>Large dataset processing</p>
</li>
</ul>
<p><strong>Pro tip:</strong> Use dynamic concurrency based on system performance: start with 3, increase if responses are fast, decrease if you get rate-limited.</p>
<ol start="3">
<li><strong>The Timeout Escape Hatch (Never Hang Forever)</strong></li>
</ol>
<p><strong>The Secret:</strong> Professional developers never trust external APIs completely. They always implement timeout strategies to prevent applications from hanging indefinitely.</p>
<p><strong>❌ Amateur Approach: Infinite Waiting</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchCriticalData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// If this API is down, your app hangs forever</span>
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/critical-data'</span>);
  <span class="hljs-keyword">return</span> data.json();
}
</code></pre>
<p><strong>✅ Professional Technique: Timeout with Fallbacks</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">withTimeout</span>(<span class="hljs-params">promise, ms, fallback = <span class="hljs-literal">null</span></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Race condition between promise and timeout
     * Whichever resolves first wins, preventing hangs
     * ================================================ */</span>
    <span class="hljs-keyword">const</span> timeout = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">if</span> (fallback !== <span class="hljs-literal">null</span>) {
        resolve(fallback);
      } <span class="hljs-keyword">else</span> {
        reject(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Operation timed out after <span class="hljs-subst">${ms}</span>ms`</span>));
      }
    }, ms);

    promise
      .then(resolve)
      .catch(reject)
      .finally(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearTimeout</span>(timeout));
  });
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchCriticalData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Multiple timeout strategies
     * Fast timeout for UX, fallback for resilience
     * ================================================ */</span>
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> withTimeout(
      fetch(<span class="hljs-string">'/api/critical-data'</span>),
      <span class="hljs-number">5000</span> <span class="hljs-comment">// 5 second timeout</span>
    );

    <span class="hljs-keyword">if</span> (!response.ok) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP <span class="hljs-subst">${response.status}</span>: <span class="hljs-subst">${response.statusText}</span>`</span>);
    }

    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Timeout on JSON parsing too
     * Network might be slow, parsing might hang
     * ================================================ */</span>
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> withTimeout(
      response.json(),
      <span class="hljs-number">2000</span> <span class="hljs-comment">// 2 seconds for JSON parsing</span>
    );

    <span class="hljs-keyword">return</span> data;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">if</span> (error.message.includes(<span class="hljs-string">'timed out'</span>)) {
      <span class="hljs-comment">// Fallback to cached data or default values</span>
      <span class="hljs-keyword">return</span> getCachedData() || getDefaultData();
    }
    <span class="hljs-keyword">throw</span> error;
  }
}
</code></pre>
<p><strong>Why this works:</strong> JavaScript’s Promise.race() behavior allows timeouts to compete with actual requests. The first to resolve wins, preventing infinite hangs while providing fallback options.</p>
<p><strong>Advanced Implementation:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> ResilientFetcher {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">options = {}</span>) {
    <span class="hljs-built_in">this</span>.defaultTimeout = options.timeout || <span class="hljs-number">5000</span>;
    <span class="hljs-built_in">this</span>.retryAttempts = options.retries || <span class="hljs-number">3</span>;
    <span class="hljs-built_in">this</span>.retryDelay = options.retryDelay || <span class="hljs-number">1000</span>;
  }

  <span class="hljs-keyword">async</span> fetchWithRetry(url, options = {}) {
    <span class="hljs-keyword">const</span> timeout = options.timeout || <span class="hljs-built_in">this</span>.defaultTimeout;

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> attempt = <span class="hljs-number">1</span>; attempt &lt;= <span class="hljs-built_in">this</span>.retryAttempts; attempt++) {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">/* ================================================
         * 🎯 ADVANCED: Exponential backoff with timeout
         * Each retry waits longer, respects server recovery
         * ================================================ */</span>
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> withTimeout(
          fetch(url, options),
          timeout
        );

        <span class="hljs-keyword">if</span> (response.ok) {
          <span class="hljs-keyword">return</span> response;
        }

        <span class="hljs-keyword">if</span> (response.status &gt;= <span class="hljs-number">500</span> &amp;&amp; attempt &lt; <span class="hljs-built_in">this</span>.retryAttempts) {
          <span class="hljs-comment">// Server error, retry with exponential backoff</span>
          <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.delay(<span class="hljs-built_in">this</span>.retryDelay * <span class="hljs-built_in">Math</span>.pow(<span class="hljs-number">2</span>, attempt - <span class="hljs-number">1</span>));
          <span class="hljs-keyword">continue</span>;
        }

        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`HTTP <span class="hljs-subst">${response.status}</span>: <span class="hljs-subst">${response.statusText}</span>`</span>);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">if</span> (attempt === <span class="hljs-built_in">this</span>.retryAttempts) {
          <span class="hljs-keyword">throw</span> error;
        }

        <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">`Attempt <span class="hljs-subst">${attempt}</span> failed:`</span>, error.message);
        <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.delay(<span class="hljs-built_in">this</span>.retryDelay);
      }
    }
  }

  delay(ms) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, ms));
  }
}
</code></pre>
<p><strong>Real-world applications:</strong></p>
<ul>
<li><p>Payment processing with strict timeouts</p>
</li>
<li><p>Real-time chat message delivery</p>
</li>
<li><p>API integrations with unreliable services</p>
</li>
<li><p>Mobile apps with poor network conditions</p>
</li>
</ul>
<p><strong>Pro tip:</strong> Use different timeout values for different operations: 2s for UI interactions, 10s for file uploads, 30s for data processing.</p>
<ol start="4">
<li><strong>The Async Initialization Pattern (Race Condition Prevention)</strong></li>
</ol>
<p><strong>The Secret:</strong> Professional developers use initialization patterns that eliminate race conditions and ensure async resources are always available when needed.</p>
<p><strong>❌ Amateur Approach: Race Condition Central</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> DataService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-built_in">this</span>.data = <span class="hljs-literal">null</span>;
    <span class="hljs-built_in">this</span>.loadData(); <span class="hljs-comment">// Fire and forget - dangerous!</span>
  }

  <span class="hljs-keyword">async</span> loadData() {
    <span class="hljs-built_in">this</span>.data = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/data'</span>).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json());
  }

  getData() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.data; <span class="hljs-comment">// Might be null if called too early</span>
  }
}
</code></pre>
<p><strong>✅ Professional Technique: Promise-Based Initialization</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> DataService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Store the Promise, not the result
     * Allows multiple consumers to await the same operation
     * ================================================ */</span>
    <span class="hljs-built_in">this</span>.dataPromise = <span class="hljs-built_in">this</span>.initializeData();
    <span class="hljs-built_in">this</span>.cache = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();
  }

  <span class="hljs-keyword">async</span> initializeData() {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">/* ================================================
       * 🎯 SECRET: Single initialization with fallbacks
       * Handles network errors gracefully on startup
       * ================================================ */</span>
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/data'</span>);
      <span class="hljs-keyword">if</span> (!response.ok) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Failed to load data: <span class="hljs-subst">${response.status}</span>`</span>);
      }

      <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

      <span class="hljs-comment">/* ================================================
       * 🎯 SECRET: Validate data structure on load
       * Prevents runtime errors from malformed responses
       * ================================================ */</span>
      <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.isValidData(data)) {
        <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">'Invalid data structure, using defaults'</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.getDefaultData();
      }

      <span class="hljs-keyword">return</span> data;
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Data initialization failed:'</span>, error);
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.getDefaultData();
    }
  }

  <span class="hljs-keyword">async</span> getData() {
    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Always return a Promise
     * Eliminates timing issues completely
     * ================================================ */</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.dataPromise;
  }

  <span class="hljs-keyword">async</span> getItem(id) {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.cache.has(id)) {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.cache.get(id);
    }

    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Wait for initialization before operations
     * Ensures data is loaded before item lookup
     * ================================================ */</span>
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.dataPromise;
    <span class="hljs-keyword">const</span> item = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.fetchItem(id);
    <span class="hljs-built_in">this</span>.cache.set(id, item);
    <span class="hljs-keyword">return</span> item;
  }
}
</code></pre>
<p><strong>Why this works:</strong> Storing the Promise instead of the result means all consumers wait for the same initialization. No matter when methods are called, they either get the data immediately or wait for it to load.</p>
<p><strong>Advanced Implementation:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> AdvancedDataService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-built_in">this</span>.state = <span class="hljs-string">'initializing'</span>;
    <span class="hljs-built_in">this</span>.initPromise = <span class="hljs-built_in">this</span>.initialize();
    <span class="hljs-built_in">this</span>.eventEmitter = <span class="hljs-keyword">new</span> EventTarget();
  }

  <span class="hljs-keyword">async</span> initialize() {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-built_in">this</span>.state = <span class="hljs-string">'loading'</span>;
      <span class="hljs-built_in">this</span>.emit(<span class="hljs-string">'stateChange'</span>, { state: <span class="hljs-string">'loading'</span> });

      <span class="hljs-comment">/* ================================================
       * 🎯 ADVANCED: Progressive initialization
       * Load critical data first, then enhance with extras
       * ================================================ */</span>
      <span class="hljs-keyword">const</span> critical = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.loadCriticalData();
      <span class="hljs-built_in">this</span>.state = <span class="hljs-string">'partial'</span>;
      <span class="hljs-built_in">this</span>.emit(<span class="hljs-string">'stateChange'</span>, { state: <span class="hljs-string">'partial'</span>, data: critical });

      <span class="hljs-keyword">const</span> optional = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.loadOptionalData();
      <span class="hljs-built_in">this</span>.state = <span class="hljs-string">'complete'</span>;
      <span class="hljs-built_in">this</span>.emit(<span class="hljs-string">'stateChange'</span>, { state: <span class="hljs-string">'complete'</span>, data: { ...critical, ...optional } });

      <span class="hljs-keyword">return</span> { ...critical, ...optional };
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">this</span>.state = <span class="hljs-string">'error'</span>;
      <span class="hljs-built_in">this</span>.emit(<span class="hljs-string">'stateChange'</span>, { state: <span class="hljs-string">'error'</span>, error });
      <span class="hljs-keyword">throw</span> error;
    }
  }

  <span class="hljs-keyword">async</span> waitForState(targetState) {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.state === targetState) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> {
      <span class="hljs-keyword">const</span> handler = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (event.detail.state === targetState) {
          <span class="hljs-built_in">this</span>.eventEmitter.removeEventListener(<span class="hljs-string">'stateChange'</span>, handler);
          resolve(event.detail);
        }
      };
      <span class="hljs-built_in">this</span>.eventEmitter.addEventListener(<span class="hljs-string">'stateChange'</span>, handler);
    });
  }

  emit(event, data) {
    <span class="hljs-built_in">this</span>.eventEmitter.dispatchEvent(
      <span class="hljs-keyword">new</span> CustomEvent(event, { detail: data })
    );
  }
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">const</span> service = <span class="hljs-keyword">new</span> AdvancedDataService();
<span class="hljs-keyword">await</span> service.waitForState(<span class="hljs-string">'partial'</span>); <span class="hljs-comment">// Can start using basic features</span>
<span class="hljs-comment">// Later...</span>
<span class="hljs-keyword">await</span> service.waitForState(<span class="hljs-string">'complete'</span>); <span class="hljs-comment">// Full functionality available</span>
</code></pre>
<p><strong>Real-world applications:</strong></p>
<ul>
<li><p>Database connection pools</p>
</li>
<li><p>Authentication token management</p>
</li>
<li><p>Configuration loading systems</p>
</li>
<li><p>Cache warming strategies</p>
</li>
</ul>
<p><strong>Pro tip:</strong> Emit events during initialization so UI components can show progressive loading states instead of blank screens.</p>
<ol start="5">
<li><strong>The Async State Machine (Complex Flow Management)</strong></li>
</ol>
<p><strong>The Secret:</strong> Professional developers treat complex async operations as state machines rather than linear flows, enabling better debugging, testing, and error recovery.</p>
<p><strong>❌ Amateur Approach: Linear Flow Chaos</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">syncUserData</span>(<span class="hljs-params">userId</span>) </span>{
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> fetchUser(userId);
  <span class="hljs-keyword">const</span> updated = <span class="hljs-keyword">await</span> updateUser(user);
  <span class="hljs-keyword">const</span> synced = <span class="hljs-keyword">await</span> syncToThirdParty(updated);
  <span class="hljs-keyword">return</span> synced;
  <span class="hljs-comment">// No visibility into where failures occur</span>
}
</code></pre>
<p><strong>✅ Professional Technique: State Machine Approach</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> UserSyncStateMachine {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">userId</span>) {
    <span class="hljs-built_in">this</span>.userId = userId;
    <span class="hljs-built_in">this</span>.state = <span class="hljs-string">'idle'</span>;
    <span class="hljs-built_in">this</span>.data = <span class="hljs-literal">null</span>;
    <span class="hljs-built_in">this</span>.error = <span class="hljs-literal">null</span>;
    <span class="hljs-built_in">this</span>.events = [];
  }

  <span class="hljs-keyword">async</span> execute() {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.transition(<span class="hljs-string">'fetching'</span>);
      <span class="hljs-comment">/* ================================================
       * 🎯 SECRET: Each state transition is explicit
       * Makes debugging and monitoring much easier
       * ================================================ */</span>
      <span class="hljs-built_in">this</span>.data = <span class="hljs-keyword">await</span> fetchUser(<span class="hljs-built_in">this</span>.userId);

      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.transition(<span class="hljs-string">'validating'</span>);
      <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.isValidUser(<span class="hljs-built_in">this</span>.data)) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Invalid user data structure'</span>);
      }

      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.transition(<span class="hljs-string">'updating'</span>);
      <span class="hljs-comment">/* ================================================
       * 🎯 SECRET: State persists through async operations
       * Can pause, resume, or restart from any point
       * ================================================ */</span>
      <span class="hljs-built_in">this</span>.data = <span class="hljs-keyword">await</span> updateUser(<span class="hljs-built_in">this</span>.data);

      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.transition(<span class="hljs-string">'syncing'</span>);
      <span class="hljs-built_in">this</span>.data = <span class="hljs-keyword">await</span> syncToThirdParty(<span class="hljs-built_in">this</span>.data);

      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.transition(<span class="hljs-string">'completed'</span>);
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.data;
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.transition(<span class="hljs-string">'error'</span>, error);
      <span class="hljs-keyword">throw</span> error;
    }
  }

  <span class="hljs-keyword">async</span> transition(newState, data = <span class="hljs-literal">null</span>) {
    <span class="hljs-keyword">const</span> previousState = <span class="hljs-built_in">this</span>.state;
    <span class="hljs-built_in">this</span>.state = newState;

    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Event logging for debugging
     * Complete audit trail of what happened when
     * ================================================ */</span>
    <span class="hljs-keyword">const</span> event = {
      timestamp: <span class="hljs-built_in">Date</span>.now(),
      <span class="hljs-keyword">from</span>: previousState,
      to: newState,
      data: data || <span class="hljs-built_in">this</span>.data,
      error: newState === <span class="hljs-string">'error'</span> ? data : <span class="hljs-literal">null</span>
    };

    <span class="hljs-built_in">this</span>.events.push(event);

    <span class="hljs-keyword">if</span> (newState === <span class="hljs-string">'error'</span>) {
      <span class="hljs-built_in">this</span>.error = data;
    }

    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Artificial delays for testing
     * Can simulate slow networks in development
     * ================================================ */</span>
    <span class="hljs-keyword">if</span> (process.env.NODE_ENV === <span class="hljs-string">'development'</span>) {
      <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">100</span>));
    }

    <span class="hljs-comment">// Emit for external monitoring</span>
    <span class="hljs-built_in">this</span>.emit(<span class="hljs-string">'stateChange'</span>, event);
  }

  emit(event, data) {
    <span class="hljs-comment">// In production, connect to logging/monitoring system</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`UserSync[<span class="hljs-subst">${<span class="hljs-built_in">this</span>.userId}</span>] <span class="hljs-subst">${event}</span>:`</span>, data);
  }

  getExecutionSummary() {
    <span class="hljs-keyword">return</span> {
      userId: <span class="hljs-built_in">this</span>.userId,
      finalState: <span class="hljs-built_in">this</span>.state,
      totalTime: <span class="hljs-built_in">this</span>.events.length &gt; <span class="hljs-number">0</span> ? 
        <span class="hljs-built_in">this</span>.events[<span class="hljs-built_in">this</span>.events.length - <span class="hljs-number">1</span>].timestamp - <span class="hljs-built_in">this</span>.events[<span class="hljs-number">0</span>].timestamp : <span class="hljs-number">0</span>,
      events: <span class="hljs-built_in">this</span>.events,
      error: <span class="hljs-built_in">this</span>.error
    };
  }
}
</code></pre>
<p><strong>Why this works:</strong> State machines provide complete visibility into async flow execution. You can pause at any state, inject errors for testing, and track exactly where failures occur. This makes complex async operations debuggable and testable.</p>
<p><strong>Advanced Implementation:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> AsyncStateMachine {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">states, initialState = 'idle'</span>) {
    <span class="hljs-built_in">this</span>.states = states;
    <span class="hljs-built_in">this</span>.currentState = initialState;
    <span class="hljs-built_in">this</span>.context = {};
    <span class="hljs-built_in">this</span>.history = [];
  }

  <span class="hljs-keyword">async</span> execute(input) {
    <span class="hljs-keyword">while</span> (<span class="hljs-built_in">this</span>.currentState !== <span class="hljs-string">'completed'</span> &amp;&amp; <span class="hljs-built_in">this</span>.currentState !== <span class="hljs-string">'error'</span>) {
      <span class="hljs-comment">/* ================================================
       * 🎯 ADVANCED: Dynamic state transition logic
       * Next state determined by current state and context
       * ================================================ */</span>
      <span class="hljs-keyword">const</span> stateConfig = <span class="hljs-built_in">this</span>.states[<span class="hljs-built_in">this</span>.currentState];
      <span class="hljs-keyword">if</span> (!stateConfig) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Unknown state: <span class="hljs-subst">${<span class="hljs-built_in">this</span>.currentState}</span>`</span>);
      }

      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> stateConfig.action(<span class="hljs-built_in">this</span>.context, input);
        <span class="hljs-keyword">const</span> nextState = stateConfig.next(result, <span class="hljs-built_in">this</span>.context);

        <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.transition(nextState, result);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-keyword">const</span> errorState = stateConfig.onError || <span class="hljs-string">'error'</span>;
        <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.transition(errorState, error);
      }
    }

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.context;
  }

  <span class="hljs-keyword">async</span> transition(newState, data) {
    <span class="hljs-keyword">const</span> event = {
      timestamp: <span class="hljs-built_in">Date</span>.now(),
      <span class="hljs-keyword">from</span>: <span class="hljs-built_in">this</span>.currentState,
      to: newState,
      data
    };

    <span class="hljs-built_in">this</span>.history.push(event);
    <span class="hljs-built_in">this</span>.currentState = newState;

    <span class="hljs-comment">/* ================================================
     * 🎯 SECRET: Context updates during transitions
     * Maintains state between async operations
     * ================================================ */</span>
    <span class="hljs-keyword">if</span> (data &amp;&amp; <span class="hljs-keyword">typeof</span> data === <span class="hljs-string">'object'</span>) {
      <span class="hljs-built_in">Object</span>.assign(<span class="hljs-built_in">this</span>.context, data);
    }
  }
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">const</span> userSyncStates = {
  idle: {
    action: <span class="hljs-keyword">async</span> () =&gt; ({ ready: <span class="hljs-literal">true</span> }),
    next: <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'fetching'</span>
  },
  fetching: {
    action: <span class="hljs-keyword">async</span> (context, input) =&gt; {
      <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> fetchUser(input.userId);
      <span class="hljs-keyword">return</span> { user };
    },
    next: <span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> result.user ? <span class="hljs-string">'updating'</span> : <span class="hljs-string">'error'</span>,
    onError: <span class="hljs-string">'error'</span>
  },
  updating: {
    action: <span class="hljs-keyword">async</span> (context) =&gt; {
      <span class="hljs-keyword">const</span> updated = <span class="hljs-keyword">await</span> updateUser(context.user);
      <span class="hljs-keyword">return</span> { user: updated };
    },
    next: <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'completed'</span>,
    onError: <span class="hljs-string">'error'</span>
  }
};

<span class="hljs-keyword">const</span> machine = <span class="hljs-keyword">new</span> AsyncStateMachine(userSyncStates);
<span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> machine.execute({ userId: <span class="hljs-number">123</span> });
</code></pre>
<p><strong>Real-world applications:</strong></p>
<ul>
<li><p>Payment processing workflows</p>
</li>
<li><p>File upload with validation steps</p>
</li>
<li><p>Multi-step form submissions</p>
</li>
<li><p>Data migration processes</p>
</li>
</ul>
<p><strong>Pro tip:</strong> Use state machines for any async flow with more than 3 steps or complex error recovery requirements. The debugging benefits alone are worth it.</p>
<p><strong>The Implementation Strategy</strong></p>
<p>Start with Secret #1 (error boundaries) in your current code. It’s the highest impact, lowest risk change.</p>
<p>Then add timeouts (#3) to any external API calls. You’ll be surprised how often they save you.</p>
<p>The queue pattern (#2) becomes essential as your app scales. Implement it before you need it.</p>
<p>Save the initialization pattern (#4) and state machine (#5) for your most critical async flows — the ones that keep you up at night when they break.</p>
<p>These aren’t just patterns; they’re the difference between code that works in development and code that survives production.</p>
<p>The professional developer who taught me these patterns said something I’ll never forget: “Async code isn’t about making things faster. It’s about making things more resilient.”</p>
<h2 id="heading-advanced-uses-of-promises">Advanced Uses Of Promises</h2>
<p>The Promise object implements eventual completion (or failure) of an asynchronous operation and its resulting values.</p>
<p>A Promise is always in one of the following states:</p>
<ul>
<li><p><strong>Pending</strong>: The initial state, neither fulfilled or rejected.</p>
</li>
<li><p><strong>Fulfilled</strong>: The operation was completed successfully.</p>
</li>
<li><p><strong>Rejected</strong>: The operation failed.</p>
</li>
</ul>
<p>Unlike “old-style“ callbacks, using Promises has the following conventions:</p>
<ul>
<li><p>Callback functions will not be called until the current event loop completes.</p>
</li>
<li><p>Even if the asynchronous operation completes (successfully or unsuccessfully), callbacks added via <code>then()</code> afterward will still be called.</p>
</li>
<li><p>You can add callbacks by calling <code>then()</code> multiple times, and they will be executed in the order they were added.</p>
</li>
</ul>
<p>The characteristic feature of Promises is <strong>chaining</strong>.</p>
<h3 id="heading-usages">Usages</h3>
<ol>
<li><strong>Promise.all([])</strong></li>
</ol>
<p>When all Promise instances in the array succeed, it returns an array of success results in the order they were requested. If any Promise fails, it enters the failure callback.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> p1 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> {
    resolve(<span class="hljs-number">1</span>);
});
<span class="hljs-keyword">const</span> p2 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> {
    resolve(<span class="hljs-number">1</span>);
});
<span class="hljs-keyword">const</span> p3 = <span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-string">'ok'</span>);

<span class="hljs-comment">// If all promises succeed, result will be an array of 3 results.</span>
<span class="hljs-keyword">const</span> result = <span class="hljs-built_in">Promise</span>.all([p1, p2, p3]); 
<span class="hljs-comment">// If one fails, the result is the failed promise's value.</span>
</code></pre>
<ol start="2">
<li><strong>Promise.allSettled([])</strong></li>
</ol>
<p>The execution will not fail; it returns an array corresponding to the status of each Promise instance in the input array.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> p1 = <span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">1</span>);
<span class="hljs-keyword">const</span> p2 = <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-number">-1</span>);
<span class="hljs-built_in">Promise</span>.allSettled([p1, p2]).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(res);
});
<span class="hljs-comment">// Output: </span>
<span class="hljs-comment">/*
   [
    { status: 'fulfilled', value: 1 },
    { status: 'rejected', reason: -1 }
   ] 
*/</span>
</code></pre>
<ol start="3">
<li><strong>Promise.any([])</strong></li>
</ol>
<p>If any Promise in the input array fulfills, the returned instance will become fulfilled and return the value of the first fulfilled promise. If all are rejected, it will become rejected.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> p1 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    reject(<span class="hljs-number">1</span>);
});
<span class="hljs-keyword">const</span> p2 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    reject(<span class="hljs-number">2</span>);
});
<span class="hljs-keyword">const</span> p3 = <span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-string">"ok"</span>);

<span class="hljs-built_in">Promise</span>.any([p1, p2, p3]).then(
    <span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(r), <span class="hljs-comment">// Outputs 'ok'</span>
    (e) =&gt; <span class="hljs-built_in">console</span>.log(e)
);
</code></pre>
<ol start="4">
<li><strong>Promise.race([])</strong></li>
</ol>
<p>As soon as any Promise in the array changes state, the state of <code>race</code> method will change accordingly; the value of the first changed Promise will be passed to the <code>race</code> method’s callback.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> p1 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> {
    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
        resolve(<span class="hljs-number">10</span>);
    }, <span class="hljs-number">3000</span>);
});
<span class="hljs-keyword">const</span> p2 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"I encountered an error"</span>);
    }, <span class="hljs-number">2000</span>);
});

<span class="hljs-built_in">Promise</span>.race([p1, p2]).then(
    <span class="hljs-function">(<span class="hljs-params">v</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(v), <span class="hljs-comment">// Outputs 10</span>
    (e) =&gt; <span class="hljs-built_in">console</span>.log(e)
);
</code></pre>
<p>Throwing an exception does not change the <code>race</code> state; it is still determined by <code>p1</code>.</p>
<h3 id="heading-advanced-uses">Advanced Uses</h3>
<p>Here are 9 advanced uses that help developers handle asynchronous operations more efficiently and elegantly.</p>
<ol>
<li><strong>Concurrency Control</strong></li>
</ol>
<p>Using <code>Promise.all</code> allows for parallel executions of multiple Promises, but to control the number of simultaneous requests, you can implement a concurrency control function.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> concurrentPromises = <span class="hljs-function">(<span class="hljs-params">promises, limit</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
        <span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">let</span> result = [];
        <span class="hljs-keyword">const</span> executor = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">if</span> (i &gt;= promises.length) {
                <span class="hljs-keyword">return</span> resolve(result);
            }
            <span class="hljs-keyword">const</span> promise = promises[i++];
            <span class="hljs-built_in">Promise</span>.resolve(promise)
                .then(<span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> {
                    result.push(value);
                    <span class="hljs-keyword">if</span> (i &lt; promises.length) {
                        executor();
                    } <span class="hljs-keyword">else</span> {
                        resolve(result);
                    }
                })
                .catch(reject);
        };
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> j = <span class="hljs-number">0</span>; j &lt; limit &amp;&amp; j &lt; promises.length; j++) {
            executor();
        }
    });
};
</code></pre>
<ol start="2">
<li><strong>Promise Timeout</strong></li>
</ol>
<p>Sometimes, you may want to a Promise to automatically reject if it does not resolve in a certain time frame. This can be implemented as follows.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> promiseWithTimeout = <span class="hljs-function">(<span class="hljs-params">promise, ms</span>) =&gt;</span>
    <span class="hljs-built_in">Promise</span>.race([
        promise,
        <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span>
            <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> reject(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Timeout after '</span> + ms + <span class="hljs-string">'ms'</span>)), ms)
        )
    ]);
</code></pre>
<ol start="3">
<li><strong>Cancelling Promises</strong></li>
</ol>
<p>Native Javascript Promises can not be cancelled, but you can simulate cancellation by introducing controllable interrupt logic.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> cancellablePromise = <span class="hljs-function"><span class="hljs-params">promise</span> =&gt;</span> {
    <span class="hljs-keyword">let</span> isCanceled = <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">const</span> wrappedPromise = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
        promise.then(
            <span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> (isCanceled ? reject({ isCanceled, value }) : resolve(value)),
            <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> (isCanceled ? reject({ isCanceled, error }) : reject(error))
        );
    });
    <span class="hljs-keyword">return</span> {
        promise: wrappedPromise,
        cancel() {
            isCanceled = <span class="hljs-literal">true</span>;
        }
    };
};
</code></pre>
<ol start="4">
<li><strong>Sequential Execution with Promises Array</strong></li>
</ol>
<p>Sometimes, you need to execute the series of Promises in order, ensuring that the previous Promise operation completes before starting the next.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> sequencePromises = <span class="hljs-function"><span class="hljs-params">promises</span> =&gt;</span>
    promises.reduce(
        <span class="hljs-function">(<span class="hljs-params">prev, next</span>) =&gt;</span> prev.then(<span class="hljs-function">() =&gt;</span> next()),
        <span class="hljs-built_in">Promise</span>.resolve()
    );
</code></pre>
<ol start="5">
<li><strong>Retry Logic for Promises</strong></li>
</ol>
<p>When a Promise is rejected due to temporary errors, you may want to retry its execution.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> retryPromise = <span class="hljs-function">(<span class="hljs-params">promiseFn, maxAttempts, interval</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> attempt = <span class="hljs-function"><span class="hljs-params">attemptNumber</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (attemptNumber === maxAttempts) {
                reject(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Max attempts reached'</span>));
                <span class="hljs-keyword">return</span>;
            }
            promiseFn().then(resolve).catch(<span class="hljs-function">() =&gt;</span> {
                <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
                    attempt(attemptNumber + <span class="hljs-number">1</span>);
                }, interval);
            });
        };
        attempt(<span class="hljs-number">0</span>);
    });
};
</code></pre>
<ol start="6">
<li><strong>Ensuring a Promise only resolves only once</strong></li>
</ol>
<p>In some cases, you may want to ensure that a Promise resolves only once, even if <code>resolve</code> is called multiple times.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> onceResolvedPromise = <span class="hljs-function"><span class="hljs-params">executor</span> =&gt;</span> {
    <span class="hljs-keyword">let</span> isResolved = <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
        executor(
            <span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> {
                <span class="hljs-keyword">if</span> (!isResolved) {
                    isResolved = <span class="hljs-literal">true</span>;
                    resolve(value);
                }
            },
            reject
        );
    });
};
</code></pre>
<ol start="7">
<li><strong>Using Promises Instead of Callbacks</strong></li>
</ol>
<p>Promises provide a more standardized and convenient way to handle asynchronous operations by replacing callback functions.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> callbackToPromise = <span class="hljs-function">(<span class="hljs-params">fn, ...args</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
        fn(...args, <span class="hljs-function">(<span class="hljs-params">error, result</span>) =&gt;</span> {
            <span class="hljs-keyword">if</span> (error) {
                reject(error);
            } <span class="hljs-keyword">else</span> {
                resolve(result);
            }
        });
    });
};
</code></pre>
<ol start="8">
<li><strong>Dynamically Generating a Promise Chain</strong></li>
</ol>
<p>In some situations, you may need to dynamically create a series of Promise chains based on different conditions.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> tasks = [task1, task2, task3]; <span class="hljs-comment">// Array of asynchronous tasks</span>

<span class="hljs-keyword">const</span> promiseChain = tasks.reduce(<span class="hljs-function">(<span class="hljs-params">chain, currentTask</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> chain.then(currentTask);
}, <span class="hljs-built_in">Promise</span>.resolve());
</code></pre>
<ol start="9">
<li><strong>Using Promises to Implement a Simple Asynchronous Lock</strong></li>
</ol>
<p>In a multi-threaded environment, you can use Promises to implement a simple asynchronous lock, ensuring that only one task can access shared resources at a time.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> lock = <span class="hljs-built_in">Promise</span>.resolve();

<span class="hljs-keyword">const</span> acquireLock = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">let</span> release;
    <span class="hljs-keyword">const</span> waitLock = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> {
        release = resolve;
    });
    <span class="hljs-keyword">const</span> tryAcquireLock = lock.then(<span class="hljs-function">() =&gt;</span> release);
    lock = waitLock;
    <span class="hljs-keyword">return</span> tryAcquireLock;
};
</code></pre>
<p>This code creates and resolves Promises continuously, implementing a simple FIFO queue to ensure that only one task can access shared resources. The <code>lock</code> variable represents whether there is a task currently executing, always pointing to the Promise of the task in progress. The <code>acquireLock</code> function requests permission to execute and creates a new Promise to wait for the current task to finish.</p>
<h2 id="heading-hoisting-in-javascript-with-let-and-const-and-how-it-differs-from-var">Hoisting in JavaScript with <code>let</code> and <code>const</code> - and how it differs from <code>var</code></h2>
<p>I used to think that hoisting only happened with the variables declared with <code>var</code>. But recently, I learned that it also happens with the variables declared with <code>let</code> and <code>const</code>.</p>
<h3 id="heading-how-hoisting-works-with-var-in-javascript">How Hoisting Works With <code>var</code> in JavaScript.</h3>
<p>Here’s how hoisting works on variables declared with <code>var</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(number)
<span class="hljs-comment">// undefined</span>

<span class="hljs-keyword">var</span> number = <span class="hljs-number">10</span>

<span class="hljs-built_in">console</span>.log(number)
<span class="hljs-comment">// 10</span>
</code></pre>
<p>The number variable is hoisted to the top of the global scope. This makes it possible to access the variable before the line it was declared, without errors.</p>
<p>But what you will notice here is that only the variable declaration (<code>var number</code>) is hoisted – the initialization (<code>= 10</code>) isn't. So when you try to access <code>number</code> before it is declared, you get the <strong>default initialization that happens with var,</strong> which is <code>undefined</code>.</p>
<h3 id="heading-how-hoisting-works-with-letconst-in-javascript">How Hoisting Works With let/const in JavaScript</h3>
<p>If you try to do the same thing with <code>let</code> and <code>const</code>, here is what happens:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(number)

<span class="hljs-keyword">let</span> number = <span class="hljs-number">10</span>
<span class="hljs-comment">// or const number = 10</span>

<span class="hljs-built_in">console</span>.log(number)
</code></pre>
<p>You get an error that says: <strong>ReferenceError: Cannot access ‘number’ before initialization</strong>.</p>
<p>So you can access the variable declared with var before the declaration without errors, but you can’t do the same thing with let and const.</p>
<p>That is why I had always thought that hoisting only happens with var, it doesn’t happen with let and const.</p>
<p>But as I said, I learned recently that variables declared with let or const are also hoisted. Let me explain.</p>
<p>Take a look at this example:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(number2)

<span class="hljs-keyword">let</span> number = <span class="hljs-number">10</span>
</code></pre>
<p>I logged a variable called number2 to the console, and I declared and initialized a variable called <code>number</code>.</p>
<p>Running this code produces this error: <strong>ReferenceError: number2 is not defined</strong></p>
<p>What do you notice between the previous error and this error? The previous error says <strong>ReferenceError: Cannot access 'number' before initialization,</strong> while this new error says <strong>ReferenceError: number2 is not defined</strong>.</p>
<p>Here's the difference. The former says "cannot access before initialization," while the latter says "is not defined".</p>
<p>What the latter means is that JavaScript has no idea about the <code>number2</code> because it’s not defined - and indeed we didn’t define it. We only defined <code>number</code>.</p>
<p>But the former doesn't say "is not defined", instead, it says, "cannot access before initialization". Here's the code again:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(number)
<span class="hljs-comment">// ReferenceError: Cannot access 'number' before initialization</span>

<span class="hljs-keyword">let</span> number = <span class="hljs-number">10</span>

<span class="hljs-built_in">console</span>.log(number)
</code></pre>
<p>That means JavaScript knows about the number variable. How does it know? Because <code>number</code> is hoisted to the top of the global scope.</p>
<p>But why does an error occur? Well, this clarifies the difference between the hoisting behavior with var and let/const.</p>
<p>Variables declared with <code>let</code> or <code>const</code> are <strong>hoisted WITHOUT a default initialization</strong>. So accessing them before the line they were declared throws <strong>ReferenceError: Cannot access 'variable' before initialization</strong>.</p>
<p>But variables declared with <code>var</code> are <strong>hoisted WITH a default initialization of undefined</strong>. So accessing them before the line they were declared returns <code>undefined</code>.</p>
<p>There is a name for the period during execution where let/const variables are hoisted but not accessible: It’s called the <strong>Temporal Dead Zone</strong>.</p>
<h2 id="heading-closure">Closure</h2>
<p>In JavaScript, functions can be nested within other functions, creating a hierarchy of scopes. Each function has its own local scope, and nested functions have access to the variables declared in their scope as well as the scopes of their outer functions. This concept is known as “nested function scope.“.</p>
<p>Let’s explore nested function scope with an example:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">outerFunction</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> outerVariable = <span class="hljs-string">"I am from the outer function"</span>;

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">innerFunction</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> innerVariable = <span class="hljs-string">"I am from the inner function"</span>;

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Inside innerFunction:"</span>, outerVariable); 
    <span class="hljs-comment">// Accesses outerVariable</span>
    outerVariable = <span class="hljs-string">"Modified in innerFunction"</span>; 
    <span class="hljs-comment">// Modifies outerVariable</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Inside innerFunction:"</span>, innerVariable); 
    <span class="hljs-comment">// Accesses innerVariable</span>
  }

  innerFunction(); <span class="hljs-comment">// Calls innerFunction</span>

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"After calling innerFunction:"</span>, outerVariable);
  <span class="hljs-comment">// Shows modified outerVariable</span>
  <span class="hljs-comment">// Uncommenting the next line will throw an error since </span>
  <span class="hljs-comment">// innerVariable is not accessible here</span>
  <span class="hljs-comment">// console.log("Outside innerFunction:", innerVariable);</span>
}

outerFunction();
</code></pre>
<p>A closure is a feature that allows a function to retain access to variables from its outer(enclosing) scope even when the outer function has finished executing. This means that the inner function “closes over“ the variables it references, and they remain accessible when the outer function has completed its execution. Closures are a powerful and fundamental concept in JavaScript. Here is a detailed example to illustrate closures:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Outer function that returns an inner function</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">outerFunction</span>(<span class="hljs-params">outerVariable</span>) </span>{
  <span class="hljs-comment">// Inner function defined inside the outer function</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">innerFunction</span>(<span class="hljs-params">innerVariable</span>) </span>{
    <span class="hljs-comment">// Accessing variables from both the outer and inner functions</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Outer variable:"</span>, outerVariable);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Inner variable:"</span>, innerVariable);
  }

  <span class="hljs-comment">// Returning the inner function (creating a closure)</span>
  <span class="hljs-keyword">return</span> innerFunction;
}

<span class="hljs-comment">// Creating closures by calling outerFunction with different arguments</span>
<span class="hljs-keyword">var</span> cls1= outerFunction(<span class="hljs-string">"cls 1"</span>);
<span class="hljs-keyword">var</span> cls2 = outerFunction(<span class="hljs-string">"cls 2"</span>);

<span class="hljs-comment">// Invoking the inner functions created by the closures</span>
cls(<span class="hljs-string">"Inner 1"</span>);<span class="hljs-comment">// Output: Outer variable: cls 1, Inner variable: Inner 1</span>
cls2(<span class="hljs-string">"Inner 2"</span>);<span class="hljs-comment">// Output: Outer variable: cls 2, Inner variable: Inner 2</span>
</code></pre>
<h2 id="heading-shallow-copy-vs-deep-copy">Shallow Copy vs Deep Copy</h2>
<p>There are two ways to clone objects in JavaScript:</p>
<ul>
<li><p><strong>Shallow copy</strong>: means that <strong>only the first level of the object is copied</strong>. Deeper levels are referenced.</p>
</li>
<li><p><strong>Deep copy</strong>: means that <strong>all levels of the object are copied</strong>. This is a true copy of the object.</p>
</li>
</ul>
<h3 id="heading-shallow-copy">Shallow Copy</h3>
<p>A shallow copy can be achieved by using the <strong>spread operator (…)</strong> or using <code>Object.assign()</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> obj = { <span class="hljs-attr">name</span>: <span class="hljs-string">'Version 1'</span>, <span class="hljs-attr">additionalInfo</span>: { <span class="hljs-attr">version</span>: <span class="hljs-number">1</span> } };

<span class="hljs-keyword">const</span> shallowCopy1 = { ...obj };
<span class="hljs-keyword">const</span> shallowCopy2 = <span class="hljs-built_in">Object</span>.assign({}, obj);
<span class="hljs-keyword">const</span> shallowCopy3 = obj;

shallowCopy1.name = <span class="hljs-string">'Version 2'</span>;
shallowCopy1.additionalInfo.version = <span class="hljs-number">2</span>;

shallowCopy2.name = <span class="hljs-string">'Version 2'</span>;
shallowCopy2.additionalInfo.version = <span class="hljs-number">2</span>;

<span class="hljs-built_in">console</span>.log(obj); <span class="hljs-comment">// { name: 'Version 1', additionalInfo: { version: 2 } }</span>
<span class="hljs-built_in">console</span>.log(shallowCopy1); <span class="hljs-comment">// { name: 'Version 2', additionalInfo: { version: 2 } }</span>
<span class="hljs-built_in">console</span>.log(shallowCopy2); <span class="hljs-comment">// { name: 'Version 2', additionalInfo: { version: 2 } }</span>

shallowCopy3.name = <span class="hljs-string">"Version 3"</span>;
<span class="hljs-built_in">console</span>.log(obj); <span class="hljs-comment">// { name: 'Version 3', additionalInfo: { version: 2 } }</span>
<span class="hljs-built_in">console</span>.log(shallowCopy3); <span class="hljs-comment">// { name: 'Version 3', additionalInfo: { version: 2 } }</span>
</code></pre>
<p>As you can see in this code snippet:</p>
<ul>
<li><p>After updating a property in the first level of the cloned object, <strong>the original property is not updated</strong>.</p>
</li>
<li><p>After updating a property on a deeper level, <strong>the original property is also updated</strong>. This happens because, in this case, deeper levels are referenced, not copied.</p>
</li>
</ul>
<h3 id="heading-deep-copy">Deep Copy</h3>
<p>A deep copy can be achieved by using <code>JSON.parse()</code> <strong>+</strong> <code>JSON.stringify()</code>:</p>
<pre><code class="lang-javascript">
<span class="hljs-keyword">const</span> obj = { <span class="hljs-attr">name</span>: <span class="hljs-string">'Version 1'</span>, <span class="hljs-attr">additionalInfo</span>: { <span class="hljs-attr">version</span>: <span class="hljs-number">1</span> } };

<span class="hljs-keyword">const</span> deepCopy = <span class="hljs-built_in">JSON</span>.parse(<span class="hljs-built_in">JSON</span>.stringify(obj));

deepCopy.name = <span class="hljs-string">'Version 2'</span>;
deepCopy.additionalInfo.version = <span class="hljs-number">2</span>;

<span class="hljs-built_in">console</span>.log(obj); <span class="hljs-comment">// { name: 'Version 1', additionalInfo: { version: 1 } }</span>
<span class="hljs-built_in">console</span>.log(deepCopy); <span class="hljs-comment">// { name: 'Version 2', additionalInfo: { version: 2 } }</span>
</code></pre>
<p>As you can see in this code snippet:</p>
<ul>
<li><p>After updating the property in the first level of the cloned objects, <strong>the original object property is not updated</strong>.</p>
</li>
<li><p>After updating the property on a deeper level, <strong>the original property is not updated</strong>. This happens because, in this case, deeper levels are also copied.</p>
</li>
</ul>
<h3 id="heading-performance">Performance</h3>
<p>For obvious reasons, shallow copies are a lot faster than deep copies. But that doesn’t mean that you should always use a shallow copy because sometimes you will also need a copy of the nested objects. So, which option should I use?</p>
<ul>
<li><p>if the depth of your object is equal to one, use a shallow copy.</p>
</li>
<li><p>if the depth of your object is bigger than one, use a deep copy.</p>
</li>
</ul>
<h2 id="heading-the-javascript-function-secret-that-professional-developers-know-but-they-never-explain-to-beginners">The JavaScript Function Secret that Professional Developers Know (But They Never Explain To Beginners)</h2>
<p>You know the basics of JavaScript functions. There is a massive gap between understanding <code>function myFunc() {}</code> and writing code that behaves predictably in production applications.</p>
<p>Most tutorials teach function syntax and parameters. Professional developers know the execution context pattern that eliminates the confusion responsible for 67% of JavaScript beginners quitting.</p>
<p>JavaScript documentation covers function creation and calling. Production code requires understanding the invisible timing behavior that determines where your functions actually exist and how they interact with the JavaScript engine.</p>
<h3 id="heading-the-secret-function-declarations-live-in-a-different-timeline">The Secret: Function Declarations Live in a Different Timeline</h3>
<p><strong>The Secret:</strong> Professional developers understand that JavaScript functions don’t just exist when you write them — they exist when JavaScript decides they exist. And those decisions follow rules that tutorials never explain.</p>
<p><strong>❌ Common Beginner Approach: Writing Functions Like Other Languages</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">/* ================================================
 * ❌ PROBLEM: Treating all functions the same
 * Impact: Unpredictable errors and confusion
 * Beginner assumption: Functions work when declared
 * ================================================ */</span>

<span class="hljs-comment">// Beginners write this and expect it to work</span>
<span class="hljs-built_in">console</span>.log(myFunction()); <span class="hljs-comment">// ??? Will this work?</span>

<span class="hljs-keyword">const</span> myFunction = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello World"</span>;
};

<span class="hljs-comment">// Result: TypeError: myFunction is not a function</span>
<span class="hljs-comment">// Beginner reaction: "JavaScript is broken!"</span>
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">/* ================================================
 * ❌ PROBLEM: Mixing function types without understanding
 * Impact: Code that works sometimes, fails other times
 * ================================================ */</span>

<span class="hljs-comment">// This works...</span>
<span class="hljs-built_in">console</span>.log(firstFunction()); <span class="hljs-comment">// "I work!"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">firstFunction</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"I work!"</span>;
}

<span class="hljs-comment">// But this doesn't...</span>
<span class="hljs-built_in">console</span>.log(secondFunction()); <span class="hljs-comment">// TypeError!</span>

<span class="hljs-keyword">const</span> secondFunction = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"I don't work!"</span>;
};

<span class="hljs-comment">// Beginner confusion: "Why do identical-looking functions behave differently?"</span>
</code></pre>
<p><strong>✅ Professional Understanding: JavaScript’s Function Timeline</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">/* ================================================
 * 🎯 SECRET: Function declarations are "hoisted" to the top
 * Why it works: JavaScript engine processes declarations first
 * Professional benefit: Predictable execution order
 * ================================================ */</span>

<span class="hljs-comment">// Professional developers know this works because of hoisting</span>
<span class="hljs-built_in">console</span>.log(professionalFunction()); <span class="hljs-comment">// "I exist before I'm written!"</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">professionalFunction</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"I exist before I'm written!"</span>;
}

<span class="hljs-comment">// JavaScript engine actually reads this as:</span>
<span class="hljs-comment">/*
function professionalFunction() {
    return "I exist before I'm written!";
}
console.log(professionalFunction());
*/</span>
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">/* ================================================
 * 🎯 SECRET: Function expressions follow variable rules
 * Why it works: Variables are hoisted, but assignments aren't
 * Professional benefit: Controlled function creation timing
 * ================================================ */</span>

<span class="hljs-comment">// Professional developers use this pattern for controlled timing</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">typeof</span> myFunc); <span class="hljs-comment">// "undefined" (variable exists, function doesn't)</span>

<span class="hljs-keyword">var</span> myFunc = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"I'm created when JavaScript reaches this line"</span>;
};

<span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">typeof</span> myFunc); <span class="hljs-comment">// "function" (now it exists)</span>

<span class="hljs-comment">// The invisible JavaScript timeline:</span>
<span class="hljs-comment">/*
var myFunc; // Hoisted declaration (undefined)
console.log(typeof myFunc); // Check type of undefined variable
myFunc = function() {...}; // Assignment happens here
console.log(typeof myFunc); // Check type of function
*/</span>
</code></pre>
<h3 id="heading-why-this-works-javascripts-two-phase-execution">Why This Works: JavaScript’s Two-Phase Execution</h3>
<p>JavaScript engines don’t execute your code line by line like you read it. They work in two phases:</p>
<p><strong>Phase 1 — Creation Phase (The Invisible Setup):</strong></p>
<ul>
<li><p>JavaScript scans for <code>function</code> declarations and creates them immediately</p>
</li>
<li><p>Variables are declared but not assigned (they exist as <code>undefined</code>)</p>
</li>
<li><p>The execution context is prepared with all declarations</p>
</li>
</ul>
<p><strong>Phase 2 — Execution Phase (Line by Line):</strong></p>
<ul>
<li><p>JavaScript runs your code line by line</p>
</li>
<li><p>Variable assignments happen when they are reached</p>
</li>
<li><p>Function expressions are assigned when reached</p>
</li>
</ul>
<p>This is why <code>function myFunc() {}</code> works anywhere in your code, but <code>const myFunc = function() {}</code> only works after the assignment line.</p>
<h3 id="heading-advanced-implementation-professional-function-patterns">Advanced Implementation: Professional Function Patterns</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">/* ================================================
 * 🎯 PRODUCTION PATTERN: Controlled function initialization
 * Professional benefit: Predictable behavior + initialization control
 * Use case: Complex applications with dependency management
 * ================================================ */</span>

<span class="hljs-comment">// Pattern 1: Immediate function availability</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">coreFunction</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Always available - use for essential utilities"</span>;
}

<span class="hljs-comment">// Pattern 2: Conditional function creation</span>
<span class="hljs-keyword">let</span> advancedFunction;

<span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.someFeature) {
    advancedFunction = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Feature-specific function - created only when needed"</span>;
    };
} <span class="hljs-keyword">else</span> {
    advancedFunction = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Fallback function - different implementation"</span>;
    };
}

<span class="hljs-comment">// Pattern 3: Module-style function organization</span>
<span class="hljs-keyword">const</span> MyModule = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Private functions (hoisted within this scope)</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">privateHelper</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Internal utility - not accessible outside"</span>;
    }

    <span class="hljs-comment">// Public interface (controlled exposure)</span>
    <span class="hljs-keyword">return</span> {
        publicMethod: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-keyword">return</span> privateHelper() + <span class="hljs-string">" - exposed through interface"</span>;
        }
    };
})();
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">/* ================================================
 * 🎯 DEBUGGING PATTERN: Understanding execution order
 * Professional benefit: Predictable debugging + clear mental model
 * ================================================ */</span>

<span class="hljs-comment">// Professional debugging technique</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"1. Script starts"</span>);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"2. Before function declaration"</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"3. Can call hoisted function:"</span>, hoistedFunc());

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"4. Before function expression"</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"5. Expression function type:"</span>, <span class="hljs-keyword">typeof</span> expressionFunc);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hoistedFunc</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"I was hoisted!"</span>;
}

<span class="hljs-keyword">const</span> expressionFunc = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"I exist now!"</span>;
};

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"6. After function expression"</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"7. Expression function type:"</span>, <span class="hljs-keyword">typeof</span> expressionFunc);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"8. Can call expression function:"</span>, expressionFunc());

<span class="hljs-comment">/* Output:
1. Script starts
2. Before function declaration  
3. Can call hoisted function: I was hoisted!
4. Before function expression
5. Expression function type: undefined
6. After function expression
7. Expression function type: function
8. Can call expression function: I exist now!
*/</span>
</code></pre>
<p><strong>Real-World Applications:</strong></p>
<ul>
<li><p><strong>React/Vue Components:</strong> Framework libraries use function hoisting for component registration systems that work regardless of declaration order</p>
</li>
<li><p><strong>Node.js Modules:</strong> Professional Node.js code uses function declarations for public APIs and expressions for private implementation details</p>
</li>
<li><p><strong>Error Prevention:</strong> Understanding hoisting eliminates 90% of “function is not defined” errors in complex applications</p>
</li>
<li><p><strong>Code Organization:</strong> Teams use hoisting rules to create predictable module loading patterns that work across different bundlers</p>
</li>
</ul>
<h3 id="heading-pro-tip">Pro Tip:</h3>
<p>Use function declarations for your main application logic (functions you want available everywhere) and function expressions for conditional or specialized functionality. This creates a clear mental model: declarations create your foundation, expressions add flexibility.</p>
<p><strong>Never mix patterns randomly.</strong> Professional teams establish rules like “utility functions use declarations, event handlers use expressions” to maintain consistency across codebases.</p>
<h2 id="heading-9-advanced-javascript-object-techniques-you-need-to-know">9 Advanced JavaScript Object Techniques You Need to Know</h2>
<p>We’ll explore <strong>nine advanced object techniques</strong> that will elevate your JavaScript skills.</p>
<h3 id="heading-1-objectfreeze-full-lockdown"><strong>🔥 1)</strong> <code>Object.freeze()</code> – Full Lockdown</h3>
<p>This is the most rigorous form of object immutability. Once frozen:</p>
<ul>
<li><p>🚫 You <strong>cannot add</strong> new properties</p>
</li>
<li><p>🚫 You <strong>cannot delete</strong> existing ones</p>
</li>
<li><p>🚫 You <strong>cannot update</strong> property values</p>
</li>
</ul>
<p>It’s an absolute deep-freeze of the object (though only shallow—nested objects aren’t frozen by default).</p>
<p><strong>📌 Example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> obj = { name: <span class="hljs-string">"Alice"</span> };
<span class="hljs-built_in">Object</span>.freeze(obj);
</code></pre>
<pre><code class="lang-typescript">obj.name = <span class="hljs-string">"Bob"</span>;      <span class="hljs-comment">// ❌ No effect</span>
obj.age = <span class="hljs-number">25</span>;          <span class="hljs-comment">// ❌ No effect</span>
<span class="hljs-keyword">delete</span> obj.name;       <span class="hljs-comment">// ❌ No effectconsole.log(obj);      // { name: "Alice" }</span>
</code></pre>
<h3 id="heading-2-objectseal-change-but-dont-add-or-remove"><strong>🔒 2)</strong> <code>Object.seal()</code> – Change, But Don’t Add or Remove</h3>
<p><code>Object.seal()</code> allows you to modify <strong>existing properties</strong> but disallows adding or <strong>deleting them</strong>.</p>
<ul>
<li><p>✅ Change values</p>
</li>
<li><p>🚫 Add new properties</p>
</li>
<li><p>🚫 Delete existing ones</p>
</li>
</ul>
<p><strong>📌 Example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> obj = { name: <span class="hljs-string">"Alice"</span> };
<span class="hljs-built_in">Object</span>.seal(obj);
</code></pre>
<pre><code class="lang-typescript">obj.name = <span class="hljs-string">"Bob"</span>;      <span class="hljs-comment">// ✅ Permitted</span>
obj.age = <span class="hljs-number">25</span>;          <span class="hljs-comment">// ❌ Not Permitted</span>
<span class="hljs-keyword">delete</span> obj.name;       <span class="hljs-comment">// ❌ Not Permittedconsole.log(obj);      // { name: "Bob" }</span>
</code></pre>
<h3 id="heading-3-objectpreventextensions-no-new-properties"><strong>🚫 3)</strong> <code>Object.preventExtensions()</code> – No New Properties</h3>
<p>This approach keeps you from adding properties to an object, but still lets you:</p>
<ul>
<li><p>✅ Change the properties</p>
</li>
<li><p>✅ Remove them</p>
</li>
<li><p>🚫 Adding new ones</p>
</li>
</ul>
<p><strong>📌 Example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> obj = { name: <span class="hljs-string">"Alice"</span> };
<span class="hljs-built_in">Object</span>.preventExtensions(obj);
</code></pre>
<pre><code class="lang-typescript">obj.name = <span class="hljs-string">"Bob"</span>;      <span class="hljs-comment">// ✅ Allowed</span>
obj.age = <span class="hljs-number">25</span>;          <span class="hljs-comment">// ❌ Not allowed</span>
<span class="hljs-keyword">delete</span> obj.name;       <span class="hljs-comment">// ✅ Allowedconsole.log(obj);      // {}</span>
</code></pre>
<p><strong>🔍 Quick Comparison Table</strong></p>
<pre><code class="lang-typescript">

| Feature                        | <span class="hljs-string">`Object.freeze()`</span> | <span class="hljs-string">`Object.seal()`</span> | <span class="hljs-string">`Object.preventExtensions()`</span> |
|-------------------------------|-------------------|------------------|-------------------------------|
| Can add properties?           | ❌ No             | ❌ No            | ❌ No                         |
| Can <span class="hljs-keyword">delete</span> properties?        | ❌ No             | ❌ No            | ✅ Yes                        |
| Can modify property values?   | ❌ No             | ✅ Yes           | ✅ Yes                        |
| Shallow or deep?              | Shallow           | Shallow          | Shallow                      |
</code></pre>
<blockquote>
<p><em>💡</em> <strong><em>Note:</em></strong> <em>All three methods only work at the</em> <strong><em>first level</em></strong> <em>— nested objects within your object will remain mutable unless you freeze them manually.</em></p>
</blockquote>
<h3 id="heading-4-object-destructuring-with-defaults">4) Object Destructuring with Defaults</h3>
<p>Destructuring allows you to extract values from objects easily, but did you know you can set default values?</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> user = { name: <span class="hljs-string">"Alice"</span>, age: <span class="hljs-number">30</span> };
<span class="hljs-keyword">const</span> { name, age, role = <span class="hljs-string">"guest"</span> } = user;

<span class="hljs-built_in">console</span>.log(role); <span class="hljs-comment">// "guest" (default value)</span>
</code></pre>
<p>This technique ensures your code doesn’t break when properties are missing.</p>
<h3 id="heading-5-computed-property-names">5) Computed Property Names</h3>
<p>You can use expressions to define object keys dynamically.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> key = <span class="hljs-string">"status"</span>;
<span class="hljs-keyword">const</span> user = {
  name: <span class="hljs-string">"Alice"</span>,
  [key]: <span class="hljs-string">"active"</span>
};

<span class="hljs-built_in">console</span>.log(user.status); <span class="hljs-comment">// "active"</span>
</code></pre>
<p>This is useful when creating objects dynamically based on user input or API responses.</p>
<h3 id="heading-6-object-merging-with-objectassign-and-spread-operator"><strong>6) Object Merging with</strong> <code>Object.assign()</code> and Spread Operator</h3>
<p>Combining multiple objects into one is a common operation.</p>
<p><strong>Example with</strong> <code>Object.assign()</code><strong>:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> obj1 = { a: <span class="hljs-number">1</span> };
<span class="hljs-keyword">const</span> obj2 = { b: <span class="hljs-number">2</span> };
<span class="hljs-keyword">const</span> merged = <span class="hljs-built_in">Object</span>.assign({}, obj1, obj2);

<span class="hljs-built_in">console</span>.log(merged); <span class="hljs-comment">// { a: 1, b: 2 }</span>
</code></pre>
<p><strong>Example with Spread Operator:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> merged2 = { ...obj1, ...obj2 };
<span class="hljs-built_in">console</span>.log(merged2); <span class="hljs-comment">// { a: 1, b: 2 }</span>
</code></pre>
<p>The spread operator is <strong>more concise and readable</strong> than <code>Object.assign()</code>.</p>
<h3 id="heading-7-object-methods-and-this-context"><strong>7) Object Methods and</strong> <code>this</code> Context</h3>
<p>Objects can have methods that use <code>this</code> to access properties.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> user = {
  name: <span class="hljs-string">"Alice"</span>,
  greet() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>!`</span>);
  }
};

user.greet(); <span class="hljs-comment">// "Hello, Alice!"</span>
</code></pre>
<p>Using arrow functions for object methods can be tricky because <strong>arrow functions do not bind their own</strong> <code>this</code>.</p>
<h3 id="heading-8-prototypal-inheritance-with-objectcreate">8) Prototypal Inheritance with <code>Object.create()</code></h3>
<p>Instead of using ES6 classes, you can directly create objects that inherit from another object.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> person = {
  greet() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello!"</span>);
  }
};

<span class="hljs-keyword">const</span> student = <span class="hljs-built_in">Object</span>.create(person);
student.study = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Studying..."</span>);
};

student.greet(); <span class="hljs-comment">// "Hello!" (inherited)</span>
student.study(); <span class="hljs-comment">// "Studying..."</span>
</code></pre>
<p>This is the <strong>basis of JavaScript’s prototype chain</strong>, allowing for memory-efficient inheritance.</p>
<h3 id="heading-9-using-objectentries-and-objectvalues-for-iteration"><strong>9) Using</strong> <code>Object.entries()</code> and <code>Object.values()</code> for Iteration</h3>
<p>Instead of looping manually over an object’s properties, use <code>Object.entries()</code> and <code>Object.values()</code>.</p>
<p><strong>Example with</strong> <code>Object.entries()</code><strong>:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> user = { name: <span class="hljs-string">"Alice"</span>, age: <span class="hljs-number">30</span> };

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> [key, value] <span class="hljs-keyword">of</span> <span class="hljs-built_in">Object</span>.entries(user)) {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${key}</span>: <span class="hljs-subst">${value}</span>`</span>);
}
<span class="hljs-comment">// name: Alice</span>
<span class="hljs-comment">// age: 30</span>
</code></pre>
<p><strong>Example with</strong> <code>Object.values()</code><strong>:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Object</span>.values(user)); <span class="hljs-comment">// ["Alice", 30]</span>
</code></pre>
<p>These methods <strong>make working with objects easier and cleaner</strong> than traditional <code>for...in</code> loops.</p>
<h2 id="heading-map">Map</h2>
<p>In earlier JavaScript, developers often used plain objects to map keys to values. However, this approach has limitations, especially when keys are not strings or symbols. Plain objects can only use strings or symbols as keys, so if you need to map non-primitive objects (like arrays or other objects) to values, it becomes cumbersome and error-prone.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> obj = {};
<span class="hljs-keyword">const</span> key = { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span> };

<span class="hljs-comment">// Trying to use a non-primitive object as a key</span>
obj[key] = <span class="hljs-string">'value'</span>;
<span class="hljs-built_in">console</span>.log(obj); <span class="hljs-comment">// Object automatically converts key to a string: '[object Object]: value'</span>
</code></pre>
<p><strong>Advice</strong>: Use <code>Map</code> when you need to map non-primitive objects or when a more robust data structure is required. Unlike plain objects, <code>Map</code> allows any type of value — primitives and — non-primitives alike — as keys.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> map = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();
<span class="hljs-keyword">const</span> key = { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span> };
<span class="hljs-comment">// Using a non-primitive object as a key in a Map</span>
map.set(key, <span class="hljs-string">'value'</span>);
<span class="hljs-built_in">console</span>.log(map.get(key)); <span class="hljs-comment">// 'value'</span>
</code></pre>
<p><strong>Why it matters:</strong> <code>Map</code> is a more flexible and predictable way of associating values to any kind of key, whether primitive or non-primitive. It preserves the type and order of keys, unlike plain objects, which convert keys to strings. This leads to more powerful and efficient handling of key-value pairs, especially when working with complex data or when you need fast lookups in larger collections.</p>
<h3 id="heading-why-is-javascripts-map-better-than-object">Why is JavaScript’s Map better than Object?</h3>
<p>JavaScript provides both Map and Object for storing key-value pairs, but Map offers significant advantages in many scenarios.</p>
<p>For more explanation, check out <a target="_blank" href="https://medium.com/@hxu0407/why-is-javascripts-map-better-than-object-4a7fc25a25ea">this article</a>.</p>
<p>Use Map when:</p>
<ul>
<li><p>Working with dynamic or complex key types</p>
</li>
<li><p>Performing frequent insertions or deletions.</p>
</li>
<li><p>Preserving insertion order</p>
</li>
<li><p>Quickly retrieving the number of entries</p>
</li>
<li><p>Avoiding prototype chain interference.</p>
</li>
</ul>
<p>Use Object when:</p>
<ul>
<li><p>Storing simple, static data.</p>
</li>
<li><p>Needing JSON serialization.</p>
</li>
<li><p>Preferring a more concise syntax for defining key-value pairs.</p>
</li>
</ul>
<h2 id="heading-symbols-for-hidden-values">Symbols for hidden values</h2>
<p>In JavaScript, objects are typically used to store key-value pairs. However, when you need to add “hidden“ or unique values to an object without risking name collisions with other properties, or you want to keep them somewhat private from external code, using Symbol can be very helpful. <code>Symbols</code> create unique keys that are not accessible via normal enumeration or accidental property lookup.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> obj = { <span class="hljs-attr">name</span>: <span class="hljs-string">'Alice'</span> };
<span class="hljs-keyword">const</span> hiddenKey = <span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'hidden'</span>);
obj[hiddenKey] = <span class="hljs-string">'Secret Value'</span>;
<span class="hljs-built_in">console</span>.log(obj.name); <span class="hljs-comment">// 'Alice'</span>
<span class="hljs-built_in">console</span>.log(obj[hiddenKey]); <span class="hljs-comment">// 'Secret Value'</span>
</code></pre>
<p><strong>Advice</strong>: Use <code>Symbol</code> when you want to add non-enumerable, hidden properties to an object. Symbols are not accessible during typical object operations like <code>for…in</code> loops or <code>Object.keys()</code>, making them perfect for internal or private data that shouldn’t be exposed accidentally.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> obj = { <span class="hljs-attr">name</span>: <span class="hljs-string">'Alice'</span> };
<span class="hljs-keyword">const</span> hiddenKey = <span class="hljs-built_in">Symbol</span>(<span class="hljs-string">'hidden'</span>);
obj[hiddenKey] = <span class="hljs-string">'Secret Value'</span>;
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Object</span>.keys(obj)); <span class="hljs-comment">// ['name'] (Symbol keys won't appear)</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Object</span>.getOwnPropertySymbols(obj)); <span class="hljs-comment">// [Symbol(hidden)] (accessible only if specifically retrieved)</span>
</code></pre>
<p><strong>Why it matters</strong>: Symbols allow you to safely add unique or “hidden“ properties to objects without worrying about key collisions or exposing internal details to other parts of the codebase. They can be especially useful in libraries or frameworks when you need to store metadata or internal states without affecting or interfering with other properties. This ensures better encapsulation and reduces the risk of accidental overwrites or misuse.</p>
<h2 id="heading-javascript-memory-leaks">JavaScript Memory Leaks</h2>
<p>JavaScript memory Leaks occur when allocated memory is not released after it is no longer needed. This can impact performance and potentially cause crashes. In JavaScript, memory management is handled by an automated garbage collector. The collector frees up memory by reclaiming it from unused objects. Automated management is helpful, but it’s not perfect. Memory leaks can still happen if objects are not properly cleared or released.</p>
<p>Over time, these leaks can slow down the application, reduce performance, or even cause it to crash.</p>
<p>Check out <a target="_blank" href="https://www.syncfusion.com/blogs/post/prevent-javascript-memory-leaks-guide?ref=dailydev">this article</a> to explore how to identify, fix, and prevent these leaks.</p>
<h2 id="heading-abortcontroller">AbortController</h2>
<p>The <code>fetch</code> API in JavaScript allows you to make HTTP requests. It is a modern alternative to the old <code>XMLHttpRequest</code>, which is now mostly outdated.</p>
<p><code>fetch</code> works with promises, meaning it returns a promise that tells you when the request is completed, either successfully or with an error.</p>
<p>Example with <code>fetch</code>:</p>
<pre><code class="lang-typescript">fetch(url)
  .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json()) <span class="hljs-comment">// Convert response to JSON</span>
  .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(data)) <span class="hljs-comment">// Log the data</span>
  .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(error)); <span class="hljs-comment">// Log any errors</span>
</code></pre>
<p>This works fine for basic requests, but sometimes you need to cancel a request that has already started.</p>
<h3 id="heading-searching-for-suggestions-as-you-type">Searching for suggestions as you type</h3>
<p>You have a search bar, and you want to show suggestions as the user types.</p>
<p>Each time the user types a character, a fetch request is made to get the suggestions based on the input. Here’s how that would look.</p>
<pre><code class="lang-typescript">fetch(<span class="hljs-string">`https://api.example.com/search?q=<span class="hljs-subst">${searchInput.value}</span>`</span>)
  .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
  .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(data))
  .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
</code></pre>
<p>The fetch request is called every time the user types, even if the user types quickly.</p>
<p>This led to multiple API requests, which is inefficient because you only care about the last requests when the user finishes typing.</p>
<h3 id="heading-solution-debounce">Solution: Debounce</h3>
<p>To fix this, you can use the debounce function, which delays the fetch request until the user stops typing for a specified amount of time (for example, 100ms). This way, you only run one request for the last typed value.</p>
<p><strong>However, there’s still an issue:</strong> if the user starts typing right after the debounce is triggered, the request will be called again.</p>
<p>This is better than calling it every time a key is pressed, but we can improve it further.</p>
<h3 id="heading-solution-abortcontroller">Solution: AbortController</h3>
<p>The introduction of the <code>AbortController</code> API in the Fetch Standard was a response to the evolving needs for better control over network requests in web applications. Historically, web APIs, especially the Fetch API introduced in 2015, lacked mechanisms to cancel ongoing requests. In the early days of AJAX and <code>XMLHttpRequest</code>, developers either had to work with timeouts or manually manage the state of requests, leading to complex and often unmanageable code bases.</p>
<p>The <code>AbortController</code> was introduced in the JavaScript API as part of the broader effort to bring more robust signal handling capabilities to developers. By providing an interoperable way to communicate with tasks running in the web environment, it enables developers to abort requests and effectively manage asynchronous operations.</p>
<p>With <code>AbortController</code>, you can cancel a request before it finishes. It's built into modern browsers.</p>
<ul>
<li><p><strong>AbortController</strong>: This object helps us control or cancel requests.</p>
</li>
<li><p><strong>AbortController.signal</strong>: A signal you use to tell fetch to cancel the request.</p>
</li>
<li><p><strong>AbortController.abort()</strong>: A method that cancels a request.</p>
</li>
</ul>
<p>We have an input field where the user can search for posts. We want to cancel previous requests if a new one is made.</p>
<p>Basic HTML Example:</p>
<pre><code class="lang-typescript">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;body&gt;
    &lt;input id=<span class="hljs-string">"search"</span> <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span> /&gt;
    &lt;script&gt;
      <span class="hljs-keyword">const</span> search = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"search"</span>);
      <span class="hljs-keyword">let</span> controller = <span class="hljs-keyword">new</span> AbortController();
      <span class="hljs-keyword">let</span> signal = controller.signal;

      <span class="hljs-keyword">const</span> fetchPost = <span class="hljs-keyword">async</span> (value, signal) =&gt; {
        <span class="hljs-keyword">try</span> {
          <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
            <span class="hljs-string">`https://jsonplaceholder.typicode.com/posts/<span class="hljs-subst">${value}</span>`</span>,
            { signal }
          );
          <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Success:"</span>, data);
        } <span class="hljs-keyword">catch</span> (error) {
          <span class="hljs-keyword">if</span> (error.name === <span class="hljs-string">"AbortError"</span>) {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Request canceled"</span>);
          } <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Something went wrong"</span>);
          }
        }
      };

      <span class="hljs-keyword">const</span> onInputChange = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> value = search.value;
        <span class="hljs-keyword">if</span> (value) {
          controller.abort(); <span class="hljs-comment">// Cancel the previous request</span>
          controller = <span class="hljs-keyword">new</span> AbortController(); <span class="hljs-comment">// Create a new controller</span>
          signal = controller.signal; <span class="hljs-comment">// Get the new signal</span>
          fetchPost(value, signal); <span class="hljs-comment">// Call the fetch function</span>
        }
      };

      search.oninput = onInputChange; <span class="hljs-comment">// Trigger the function on input</span>
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p><code>AbortController</code> ensures that we cancel any ongoing requests before making a new one, improving performance, and preventing unnecessary API calls.</p>
<h2 id="heading-advanced-oop-concepts">Advanced OOP Concepts</h2>
<p>Object-Oriented Programming (OOP) is a paradigm that uses objects and classes to structure code. In JavaScript, OOP principles can help manage and organize code more efficiently, especially for complex applications.</p>
<h3 id="heading-what-is-object-oriented-programming">What is Object-Oriented Programming?</h3>
<p>Object-oriented programming is a programming paradigm based on the concept of “objects“, which can contain data (attributes) and code (methods). OOP helps in modeling real-world entities and interactions, making it easier to manage and maintain code.</p>
<p>Key Concepts of OOP:</p>
<ul>
<li><p>Encapsulation: Bundling data and methods that operate on the data within one unit (i.e a class)</p>
</li>
<li><p>Abstraction: Hiding the complex implementation details and showing only the essential features of an object.</p>
</li>
<li><p>Inheritance: Mechanism by which one class can inherit the properties and methods of another class.</p>
</li>
<li><p>Polymorphism: The Ability of different objects to respond to the same method in different ways.</p>
</li>
</ul>
<h3 id="heading-javascript-and-oop">JavaScript and OOP</h3>
<p>JavaScript is a versatile language that supports OOP concepts through its own syntax and features. Let’s explore how JavaScript implements these features.</p>
<p><strong>Encapsulation</strong></p>
<p>In JavaScript, encapsulation is achieved using classes and objects. A class is a blueprint for creating objects, and an object is an instance of a class</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
  <span class="hljs-comment">// Constructor to initialize object properties</span>
  <span class="hljs-keyword">constructor</span>(name, age) {
    <span class="hljs-built_in">this</span>.name = name;
    <span class="hljs-built_in">this</span>.age = age;
  }

  <span class="hljs-comment">// Method to display person's details</span>
  greet() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, my name is <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> and I am <span class="hljs-subst">${<span class="hljs-built_in">this</span>.age}</span> years old.`</span>);
  }
}

<span class="hljs-comment">// Creating an instance of the Person class</span>
<span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'Alice'</span>, <span class="hljs-number">30</span>);
person1.greet(); <span class="hljs-comment">// Output: Hello, my name is Alice and I am 30 years old.</span>
</code></pre>
<p>In this example, <code>Person</code> is a class with a constructor and methods. The <code>greet</code> method encapsulates the behavior of greeting and the <code>name</code> and <code>age</code> properties encapsulate the data.</p>
<p><strong>Abstraction</strong></p>
<p>Abstraction is about hiding complex implementation details and showing only the necessary features. In JavaScript, abstraction is achieved by using classes and methods that abstract away complex functionalities.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span> </span>{
  <span class="hljs-keyword">constructor</span>(make, model) {
    <span class="hljs-built_in">this</span>.make = make;
    <span class="hljs-built_in">this</span>.model = model;
  }

  <span class="hljs-comment">// Abstract method</span>
  startEngine() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Engine started.'</span>);
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ElectricCar</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Car</span> </span>{
  startEngine() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Electric engine started silently.'</span>);
  }
}

<span class="hljs-keyword">const</span> myCar = <span class="hljs-keyword">new</span> ElectricCar(<span class="hljs-string">'Tesla'</span>, <span class="hljs-string">'Model S'</span>);
myCar.startEngine(); <span class="hljs-comment">// Output: Electric engine started silently.</span>
</code></pre>
<p>Here, the <code>Car</code> class provides an abstract method <code>startEngine</code>. The <code>ElectricCar</code> subclass provides a specific implementation of <code>startEngine</code>, hiding the complexity of starting an electric engine.</p>
<p><strong>Inheritance</strong></p>
<p>Inheritance allows one class to inherit properties and methods from another class. In JavaScript, this is achieved by using <code>extends</code> keyword.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Animal</span> </span>{
  <span class="hljs-keyword">constructor</span>(name) {
    <span class="hljs-built_in">this</span>.name = name;
  }

  speak() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> makes a noise.`</span>);
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Animal</span> </span>{
  speak() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> barks.`</span>);
  }
}

<span class="hljs-keyword">const</span> myDog = <span class="hljs-keyword">new</span> Dog(<span class="hljs-string">'Rex'</span>);
myDog.speak(); <span class="hljs-comment">// Output: Rex barks.</span>
</code></pre>
<p>In this example, <code>Dog</code> inherits from <code>Animal</code> and overrides the speak method to provide the specific implementation for dogs.</p>
<p><strong>Polymorphism</strong></p>
<p>Polymorphism allows objects of different classes to be treated as objects of a common superclass. In JavaScript, this is achieved through method overriding and dynamic method dispatch.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span> </span>{
  draw() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Drawing a shape.'</span>);
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Shape</span> </span>{
  draw() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Drawing a circle.'</span>);
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Square</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Shape</span> </span>{
  draw() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Drawing a square.'</span>);
  }
}

<span class="hljs-keyword">const</span> shapes = [<span class="hljs-keyword">new</span> Circle(), <span class="hljs-keyword">new</span> Square()];

shapes.forEach(<span class="hljs-function"><span class="hljs-params">shape</span> =&gt;</span> shape.draw());
<span class="hljs-comment">// Output:</span>
<span class="hljs-comment">// Drawing a circle.</span>
<span class="hljs-comment">// Drawing a square.</span>
</code></pre>
<p>Here, the <code>draw</code> method is polymorphic: different shapes provide different implementations of <code>draw</code>, but they can be used interchangeably.</p>
<h3 id="heading-javascript-oop-features-and-syntax">JavaScript OOP Features and Syntax</h3>
<p>JavaScript provides several features to support OOP:</p>
<ul>
<li><p>Classes: Introduced in ES6, classes provide a clear syntax for creating objects and handling inheritance.</p>
</li>
<li><p>Constructors: Special methods used to initialize new objects.</p>
</li>
<li><p>Getters and Setters: Special methods for defining how to set and get object properties.</p>
</li>
<li><p>Static methods: Methods that belong to the class rather than any instance of the class.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> </span>{
  <span class="hljs-keyword">constructor</span>(width, height) {
    <span class="hljs-built_in">this</span>.width = width;
    <span class="hljs-built_in">this</span>.height = height;
  }

  <span class="hljs-comment">// Getter for area</span>
  <span class="hljs-keyword">get</span> <span class="hljs-title">area</span>() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.width * <span class="hljs-built_in">this</span>.height;
  }

  <span class="hljs-comment">// Setter for width</span>
  <span class="hljs-keyword">set</span> <span class="hljs-title">width</span>(<span class="hljs-params">value</span>) {
    <span class="hljs-keyword">if</span> (value &gt; <span class="hljs-number">0</span>) {
      <span class="hljs-built_in">this</span>._width = value;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Width must be positive.'</span>);
    }
  }

  <span class="hljs-comment">// Static method</span>
  <span class="hljs-keyword">static</span> describe() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A rectangle is a four-sided shape.'</span>);
  }
}

<span class="hljs-keyword">const</span> myRectangle = <span class="hljs-keyword">new</span> Rectangle(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>);
<span class="hljs-built_in">console</span>.log(myRectangle.area); <span class="hljs-comment">// Output: 50</span>
Rectangle.describe(); <span class="hljs-comment">// Output: A rectangle is a four-sided shape.</span>
</code></pre>
<p>In this example:</p>
<ul>
<li><p><code>area</code> is a getter that computes the area of the rectangle.</p>
</li>
<li><p><code>width</code> is a setter that validates the width before setting it.</p>
</li>
<li><p><code>describe</code> is a static method that provides information about rectangles.</p>
</li>
</ul>
<h2 id="heading-this-keyword"><code>this</code> Keyword</h2>
<p>In JavaScript, the <code>this</code> keyword refers to the current execution context or the object that a function is a method of. The value of <code>this</code> is determined by how a function is called. Understanding <code>this</code> is crucial for writing object-oriented and functional JavaScript code. Here are the main scenarios in which the value of <code>this</code> is determined, along with examples:</p>
<h3 id="heading-global-context">Global Context:</h3>
<p>When used outside of any function, <code>this</code> refers to the global object(e.g, <code>window</code> in browser or <code>global</code> in Node.js):</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>); <span class="hljs-comment">// Output: Window (in a browser environment)</span>
</code></pre>
<h3 id="heading-function-context">Function Context:</h3>
<ul>
<li><p>A function <code>this</code> can have different values depending on how the function is invoked.</p>
</li>
<li><p>In a regular function, <code>this</code> is determined by the calling context. If the function is not a method of an object or is not called with <code>call</code>, <code>apply</code>, or <code>bind</code>, it defaults to the global object (or <code>undefined</code> in strict mode).</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">showThis</span>(<span class="hljs-params"></span>) </span>{   
  <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>); 
}  
showThis(); <span class="hljs-comment">// Output: Window (in a browser environment)</span>
</code></pre>
<h3 id="heading-method-context">Method Context</h3>
<p>When a function is a method of an object, <code>this</code> refers to the objects on which the method is called.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> person = {  
 <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span>,   
 <span class="hljs-attr">sayHello</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{     
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello, my name is "</span> + <span class="hljs-built_in">this</span>.name);   
 } 
};  
person.sayHello(); <span class="hljs-comment">// Output: Hello, my name is John</span>
</code></pre>
<h3 id="heading-constructor-context">Constructor Context</h3>
<p>When a function is used as a constructor with the <code>new</code> keyword, <code>this</code> refers to the newly created object.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dog</span>(<span class="hljs-params">name</span>) </span>{   
  <span class="hljs-built_in">this</span>.name = name; 
}  
<span class="hljs-keyword">var</span> myDog = <span class="hljs-keyword">new</span> Dog(<span class="hljs-string">'Buddy'</span>); 
<span class="hljs-built_in">console</span>.log(myDog.name); <span class="hljs-comment">// Output: Buddy</span>
</code></pre>
<h3 id="heading-event-handler-context">Event Handler Context</h3>
<p>In event handlers, <code>this</code> often refers to the element that triggered the event.</p>
<pre><code class="lang-javascript">&lt;button id=<span class="hljs-string">"myButton"</span>&gt;Click me&lt;/button&gt;  
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">   
<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'myButton'</span>).addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =&gt;</span> {     
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>); <span class="hljs-comment">// Output: &lt;button&gt; element   }); </span>
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
</code></pre>
<h3 id="heading-arrow-function-context">Arrow Function Context</h3>
<p>Arrow functions do not have their <code>this</code> context. Instead, they inherit <code>this</code> from enclosing scope (lexical scoping).</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">outerFunction</span>(<span class="hljs-params"></span>) </span>{   
  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {     
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>);   
  }; 
}  
<span class="hljs-keyword">var</span> arrowFunction = outerFunction(); 
arrowFunction(); <span class="hljs-comment">// Output: The value of `this` from outerFunction</span>
</code></pre>
<h2 id="heading-advanced-javascript-functions-to-improve-code-quality">Advanced JavaScript Functions To Improve Code Quality</h2>
<p>There are some built-in features to create some of the most powerful functions to <strong>boost your performance</strong> and make your code look much more beautiful. I will cover Debounce, Throttle, Once, Memoize, Curry, Partial, Pipe, Compose, Pick, Omit, and Zip, which you can save in the utility file/class to optimize your code quality as a JavaScript developer.</p>
<p><strong>Although the functions are explained using JavaScript, they could be easily implemented in any programming language. Once the concept of the different functions is understood, it can be applied everywhere.</strong></p>
<p>Furthermore, the functions (or concepts) described in this post are <strong>often asked in technical interviews</strong>.</p>
<p>Whether you are a beginner or an experienced senior developer, these functions will optimize your code and coding experience. They will make working with JavaScript more enjoyable and efficient.</p>
<h3 id="heading-debounce-throttle">Debounce, Throttle</h3>
<p>Check out my previous article on this <a target="_blank" href="https://blog.tuanhadev.tech/react-javascript-optimization-techniques-part-i#heading-debouncing-throttling">link</a>.</p>
<h3 id="heading-once">Once</h3>
<p>The Once function is a method that will prevent execution if already been called. This is especially useful when working with event listeners, where you often encounter functions that should only run once. Instead of removing event listeners every time, you can use the Once function in JavaScript.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">once</span>(<span class="hljs-params">func</span>) </span>{
  <span class="hljs-keyword">let</span> ran = <span class="hljs-literal">false</span>;
  <span class="hljs-keyword">let</span> result;
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (ran) <span class="hljs-keyword">return</span> result;
    result = func.apply(<span class="hljs-built_in">this</span>, <span class="hljs-built_in">arguments</span>);
    ran = <span class="hljs-literal">true</span>;
    <span class="hljs-keyword">return</span> result;
  };
}
</code></pre>
<p>For example, you can have a function that sends a request to the server to load some data. With the <code>once()</code> function, you could ensure that the request is not called multiple times if the user keeps clicking the button. <strong>This will avoid performance issues.</strong></p>
<p>Without the <code>once()</code> function, you would remove the click listener instantly after the request is sent to prevent sending the request again.</p>
<p>Applying the <code>once()</code> function to any code will look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the function that sends the request</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">requestSomeData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Send the request...</span>
}

<span class="hljs-comment">// Create a version of the function that can only be called once</span>
<span class="hljs-keyword">const</span> sendRequestOnce = once(sendRequest);

<span class="hljs-comment">// Listen for clicks on a button and call the "once" function</span>
<span class="hljs-keyword">const</span> button = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"button"</span>);
button.addEventListener(<span class="hljs-string">"click"</span>, sendRequestOnce);
</code></pre>
<p>In this example, the <code>requestSomeData</code> function will be called once, even if the user clicks the button multiple times.</p>
<h3 id="heading-memoize">Memoize</h3>
<p>Memoize is a JavaScript function that is used to cache the results of a given function to prevent calling computationally expensive routines multiple times with the same arguments.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">memoize</span>(<span class="hljs-params">func</span>) </span>{
  <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> key = <span class="hljs-built_in">JSON</span>.stringify(<span class="hljs-built_in">arguments</span>);
    <span class="hljs-keyword">if</span> (cache.has(key)) {
        <span class="hljs-keyword">return</span> cache.get(key);
    }
    <span class="hljs-keyword">const</span> result = func.apply(<span class="hljs-built_in">this</span>, <span class="hljs-built_in">arguments</span>);
    cache.set(key, result);
    <span class="hljs-keyword">return</span> result;
  };
}
</code></pre>
<p>This <code>memoize()</code> function will cache the result of a given function and uses the arguments as key to retrieve the result if called again with the same arguments.</p>
<p>Now, if you have a function that performs a complex calculation that is based on an input variable, you can use <code>memoize()</code> function to cache the results and retrieve them instantly if called multiple times with the same input.</p>
<p>To see the benefits of the <code>memoize()</code> function, you can use it to calculate the Fibonacci numbers:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the function that performs the calculation</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fibonacci</span>(<span class="hljs-params">n</span>) </span>{
    <span class="hljs-keyword">if</span> (n &lt; <span class="hljs-number">2</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
    <span class="hljs-keyword">return</span> fibonacci(n - <span class="hljs-number">1</span>) + fibonacci(n - <span class="hljs-number">2</span>);
}

<span class="hljs-comment">// Create a memoized version of the function</span>
<span class="hljs-keyword">const</span> memoizedFibonacci = memoize(fibonacci);

<span class="hljs-comment">// Call the memoized function with multiple input values</span>
<span class="hljs-built_in">console</span>.time(<span class="hljs-string">'total'</span>)
<span class="hljs-built_in">console</span>.time(<span class="hljs-string">'sub1'</span>)
<span class="hljs-keyword">const</span> result1 = memoizedFibonacci(<span class="hljs-number">30</span>);
<span class="hljs-built_in">console</span>.timeEnd(<span class="hljs-string">'sub1'</span>)
<span class="hljs-built_in">console</span>.time(<span class="hljs-string">'sub2'</span>)
<span class="hljs-keyword">const</span> result2 = memoizedFibonacci(<span class="hljs-number">29</span>);
<span class="hljs-built_in">console</span>.timeEnd(<span class="hljs-string">'sub2'</span>)
<span class="hljs-built_in">console</span>.time(<span class="hljs-string">'sub3'</span>)
<span class="hljs-keyword">const</span> result3 = memoizedFibonacci(<span class="hljs-number">30</span>);
<span class="hljs-built_in">console</span>.timeEnd(<span class="hljs-string">'sub3'</span>)
<span class="hljs-built_in">console</span>.timeEnd(<span class="hljs-string">'total'</span>)
</code></pre>
<p>In this example, the <code>Fibonacci()</code> function will be converted into a <code>memoizedFibonacci</code> function. Then the <code>memoized()</code> function will be called, and the execution time will be logged to the console.</p>
<p>The output will look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732791820313/5091ea38-cef8-4028-a878-c214922a60e7.webp" alt class="image--center mx-auto" /></p>
<p>Although the second call only calculated the Fibonacci number of 29 it took much longer than calculating the Fibonacci number of 30 a second time because it was cached by the <code>memoize()</code> function.</p>
<h3 id="heading-curry">Curry</h3>
<p>The Curry function (also known as Currying) is an advanced JavaScript function used to create a new function from an existing one by “pre-filling“ some of its arguments. Currying is often used when working with functions that take multiple arguments and transform them into functions that take some arguments because the other will always stay the same.</p>
<p>Using the Curry function has several benefits:</p>
<ul>
<li><p>It helps to avoid using the same variable again and again</p>
</li>
<li><p>It makes the code more readable</p>
</li>
<li><p>It divides functions into multiple smaller functions that can handle one responsibility</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">curry</span>(<span class="hljs-params">func, arity = func.length</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">curried</span>(<span class="hljs-params">...args</span>) </span>{
    <span class="hljs-keyword">if</span> (args.length &gt;= arity) <span class="hljs-keyword">return</span> func(...args);
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">...moreArgs</span>) </span>{
      <span class="hljs-keyword">return</span> curried(...args, ...moreArgs);
    };
  };
}
</code></pre>
<p>This Curry function takes another function (<code>func</code>) and an optional argument <code>arity</code> that defaults to the length of <code>func</code>’s arguments. It returns a new function (<code>curried</code>) that can be called with a <code>arity</code> number of arguments. If not all arguments have been supplied, it returns a new function that can be called with more arguments until all required arguments have been provided. When all arguments are supplied, the original function (<code>func</code>) is called, and its result will be returned.</p>
<p>To understand the benefits of the Curry function, you could think of a method to calculate the distance between two points in a plane. Using a Curry function, you can create a new function that will only require one of these points, making it easier to use.</p>
<p>The following snippet will show how the previously defined curry function is used to optimize the reliability of the implementation:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the function that calculates the distance between two points</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">distance</span>(<span class="hljs-params">x1, y1, x2, y2</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.sqrt((x2 - x1) ** <span class="hljs-number">2</span> + (y2 - y1) ** <span class="hljs-number">2</span>);
}

<span class="hljs-comment">// Create a curried version of the function that only requires one of the points</span>
<span class="hljs-keyword">const</span> distanceFromOrigin = curry(distance, <span class="hljs-number">3</span>)(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>);

<span class="hljs-comment">// Call the curried function with the other point</span>
<span class="hljs-keyword">const</span> d1 = distanceFromOrigin(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">const</span> d2 = distanceFromOrigin(<span class="hljs-number">2</span>, <span class="hljs-number">2</span>);
</code></pre>
<p>In this example, a curried version of the <code>distance</code> function is created (<code>distanceFromOrigin</code>) by using the <code>curry</code> function and passing <code>distance</code> as the first argument and 3 as the second argument (<code>arity</code>). Also, it will call the curried function with <code>0,0</code> as the first two arguments.</p>
<p>The resulting function <code>distanceFromOrigin</code> is now a new function that needs only two arguments, and will always use <code>0,0</code> as the first point.</p>
<h3 id="heading-partial">Partial</h3>
<p>The Partial function in JavaScript is similar to the Curry function. The significant difference between Curry and Partial is that a call to a Partial function returns the result instantly instead of returning another function down the currying chain.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">partial</span>(<span class="hljs-params">func, ...args</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">partiallyApplied</span>(<span class="hljs-params">...moreArgs</span>) </span>{
    <span class="hljs-keyword">return</span> func(...args, ...moreArgs);
  }
}
</code></pre>
<p>The <code>partial</code> function in JavaScript typically takes an existing function, one or more input arguments, and returns a new function that calls the original function with the additional arguments passed in when the new function is called.</p>
<p>In the following use case, a <code>calculate</code> function will be pre-filled with the first two arguments to generate a new function with a more readable name.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the function that calculates something</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculate</span>(<span class="hljs-params">x, y, z</span>) </span>{
    <span class="hljs-keyword">return</span> (x + y) * z
}

<span class="hljs-comment">// Create a partially applied version of the function the last argument</span>
<span class="hljs-keyword">const</span> multiply10By = partial(calculate, <span class="hljs-number">8</span>, <span class="hljs-number">2</span>);

<span class="hljs-comment">// Call the partially applied function with the number of iterations</span>
<span class="hljs-keyword">const</span> result = multiply10By(<span class="hljs-number">5</span>);
</code></pre>
<p>In this example, the <code>multiply10By</code> function is created by partially applying the generic <code>calculate</code> function and pre-filling the first arguments with 8 and 2. This will create a new function <code>multiply10By</code> that only requires one argument, specifying the amount of 10 multiplication that has to be done. Also, it will make the code more readable and understandable.</p>
<h3 id="heading-pipe">Pipe</h3>
<p>The Pipe function is a utility function used to chain multiple functions and pass the output of one to the next one in the chain. It’s similar to the Unix pipe operator and will apply all functions left to right by using the JavaScript <code>reduce()</code> function.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">pipe</span>(<span class="hljs-params">...funcs</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">piped</span>(<span class="hljs-params">...args</span>) </span>{
    <span class="hljs-keyword">return</span> funcs.reduce(<span class="hljs-function">(<span class="hljs-params">result, func</span>) =&gt;</span> [func.call(<span class="hljs-built_in">this</span>, ...result)], args)[<span class="hljs-number">0</span>];
  };
}
</code></pre>
<p>To understand the pipe function, imagine you have three functions:</p>
<ul>
<li><p>Add a Prefix to a String</p>
</li>
<li><p>Add a Suffix to a String</p>
</li>
<li><p>Convert a String to Uppercase</p>
</li>
</ul>
<p>Then you can use the pipe function to create a new function that will apply every single one from left to right to a String.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the functions that add to the string</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addPrefix</span>(<span class="hljs-params">str</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-string">"prefix-"</span> + str;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addSuffix</span>(<span class="hljs-params">str</span>) </span>{
  <span class="hljs-keyword">return</span> str + <span class="hljs-string">"-suffix"</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toUppercase</span>(<span class="hljs-params">str</span>) </span>{
    <span class="hljs-keyword">return</span> str.toUpperCase()
}

<span class="hljs-comment">// Create a piped function that applies the three functions in the correct order</span>
<span class="hljs-keyword">const</span> decorated1 = pipe(addPrefix, addSuffix, toUppercase);
<span class="hljs-keyword">const</span> decorated2 = pipe(toUppercase, addPrefix, addSuffix);

<span class="hljs-comment">// Call the piped function with the input string</span>
<span class="hljs-keyword">const</span> result1 = decorated1(<span class="hljs-string">"hello"</span>);        <span class="hljs-comment">// PREFIX-HELLO-SUFFIX</span>
<span class="hljs-keyword">const</span> result2 = decorated2(<span class="hljs-string">"hello"</span>);        <span class="hljs-comment">// prefix-HELLO-suffix</span>
</code></pre>
<p>In this example, the decorated1 and decorated2 functions are created by piping the <code>addPrefix</code>, <code>addSuffix</code>, and <code>toUppercase</code> functions in different orders. The new functions, that are created can be called with the input string to apply the three original ones in the given order. The resulting output strings will be different because the order provided in the pipe function is different.</p>
<h3 id="heading-compose">Compose</h3>
<p>The Compose function is the same as the Pipe function, but it will use <code>reduceRight</code> to apply all functions:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">compose</span>(<span class="hljs-params">...funcs</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">composed</span>(<span class="hljs-params">...args</span>) </span>{
    <span class="hljs-keyword">return</span> funcs.reduceRight(<span class="hljs-function">(<span class="hljs-params">result, func</span>) =&gt;</span> [func.call(<span class="hljs-built_in">this</span>, ...result)], args)[<span class="hljs-number">0</span>];
  };
}
</code></pre>
<p>This will result in the same functionality, but the functions are applied from right to left.</p>
<h3 id="heading-pick">Pick</h3>
<p>The Pick function in JavaScript is used to select specific values from an object. It is a way to create a new object by selecting certain properties from a provided object. It is a functional programming technique that allows extracting a subset of properties from any object if the properties are available.</p>
<p>Here’s the implementation of the Pick function:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">pick</span>(<span class="hljs-params">obj, keys</span>) </span>{
  <span class="hljs-keyword">return</span> keys.reduce(<span class="hljs-function">(<span class="hljs-params">acc, key</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (obj.hasOwnProperty(key)) {
      acc[key] = obj[key];
    }
    <span class="hljs-keyword">return</span> acc;
  }, {});
}
</code></pre>
<p>This function takes two parameters:</p>
<ul>
<li><p><code>obj</code>: Original object which the new object will be created</p>
</li>
<li><p><code>keys</code>: Array of keys to select into the new object.</p>
</li>
</ul>
<p>To create a new object, the function will use the <code>reduce()</code> method to iterate over the keys and compare them to the original object’s properties. If a value is present, it will be added to the accumulator object in the reduce function, which was initialized with <code>{}</code>.</p>
<p>At the end of the reduce function, the accumulator object will be the new object and will contain only the specified properties that were in <code>keys</code> array.</p>
<p>This function is useful if you want to avoid over-fetching data. With the Pick function, you can retrieve any objects from the database and then only <code>pick()</code> needed properties and return them to the caller.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> obj = {
    <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Paul'</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">'82ada72easd7'</span>,
    <span class="hljs-attr">role</span>: <span class="hljs-string">'admin'</span>,
    <span class="hljs-attr">website</span>: <span class="hljs-string">'https://www.paulsblog.dev'</span>,
};

<span class="hljs-keyword">const</span> selected = pick(obj, [<span class="hljs-string">'name'</span>, <span class="hljs-string">'website'</span>]);
<span class="hljs-built_in">console</span>.log(selected); <span class="hljs-comment">// { name: 'Paul', website: 'https://www.paulsblog.dev' }</span>
</code></pre>
<p>This function will use the <code>pick()</code> function to create a new object only containing <code>name</code> and <code>website</code> which can be returned to the caller without exposing the <code>role</code>, and <code>password</code>, or the <code>id</code>.</p>
<h3 id="heading-omit">Omit</h3>
<p>The Omit function is the opposite of the Pick function, as it will remove certain properties from an existing object. That means you can avoid overfetching by hiding properties. It can be used as a replacement for the Pick function if the number of properties to hide is smaller than the number of properties to pick.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">omit</span>(<span class="hljs-params">obj, keys</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.keys(obj)
    .filter(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> !keys.includes(key))
    .reduce(<span class="hljs-function">(<span class="hljs-params">acc, key</span>) =&gt;</span> {
      acc[key] = obj[key];
      <span class="hljs-keyword">return</span> acc;
    }, {});
}
</code></pre>
<p>This function takes two parameters:</p>
<ul>
<li><p><code>obj</code>: Original object from which the new object will be created from</p>
</li>
<li><p><code>keys</code>: An array of keys that won’t be in the new object.</p>
</li>
</ul>
<p>To create a new object and remove the properties the <code>Object.keys()</code> function is used to create an array of keys for the original object. Then Javascript <code>filter()</code> function will remove every key that was specified in the <code>keys</code> argument. With the <code>reduce</code> function, the remaining keys will be iterated, and a new object is returned that only consists of every key to provided in the <code>keys</code> array.</p>
<p>In practice, you can use it if you have a large user object where you only want to remove the ID:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> obj = {
    <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">name</span>: <span class="hljs-string">'Paul'</span>,
    <span class="hljs-attr">job</span>: <span class="hljs-string">'Senior Engineer'</span>,
    <span class="hljs-attr">twitter</span>: <span class="hljs-string">'https://www.twitter.com/paulknulst'</span>,
    <span class="hljs-attr">website</span>: <span class="hljs-string">'https://www.paulsblog.dev'</span>,
};

<span class="hljs-keyword">const</span> selected = omit(obj, [<span class="hljs-string">'id'</span>]);
<span class="hljs-built_in">console</span>.log(selected); <span class="hljs-comment">// {name: 'Paul', job: 'Senior Engineer', twitter: 'https://www.twitter.com/paulknulst', website: 'https://www.paulsblog.dev'}</span>
</code></pre>
<p>In this example, the <code>omit()</code> function is used to remove the id property and retrieve an object which will make your code more readable than using a for loop, setting <code>obj.id = undefined</code> or using <code>pick()</code> and supplying every attribute to pick.</p>
<h3 id="heading-zip">Zip</h3>
<p>The Zip function is a JavaScript function that matches each passed array of elements to another array element and is used to combine multiple arrays into a single array of tuples. The resulting array will contain the corresponding elements from each array. Often, this functionality is used when working with data from multiple sources that need to be merged or correlated in some way.</p>
<p>Unlike Python, JavaScript doesn't provide the Zip function out of the box. But the implementation is easy:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">zip</span>(<span class="hljs-params">...arrays</span>) </span>{
  <span class="hljs-keyword">const</span> maxLength = <span class="hljs-built_in">Math</span>.max(...arrays.map(<span class="hljs-function"><span class="hljs-params">array</span> =&gt;</span> array.length));
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Array</span>.from({ <span class="hljs-attr">length</span>: maxLength }).map(<span class="hljs-function">(<span class="hljs-params">_, i</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Array</span>.from({ <span class="hljs-attr">length</span>: arrays.length }, <span class="hljs-function">(<span class="hljs-params">_, j</span>) =&gt;</span> arrays[j][i]);
  });
}
</code></pre>
<p>This JavaScript snippet will create a new array of arrays when every subarray is composed of the elements of the provided arrays. This means that every element of the original array will be mapped to another element from another original array in the same index.</p>
<p>For example, you could have three arrays that:</p>
<ul>
<li><p>contains the x coordinate</p>
</li>
<li><p>contains the y coordinate</p>
</li>
<li><p>contains the z coordinate'</p>
</li>
</ul>
<p>Without a zip function, you would manually loop through the arrays and pair the x,y, and z elements. But, by using the zip function, you can pass the original arrays and generate a new array of (x,y,z) tuples.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Define the arrays that contain the coordinates</span>
<span class="hljs-keyword">const</span> xCoordinates = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>];
<span class="hljs-keyword">const</span> yCoordinates = [<span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>];
<span class="hljs-keyword">const</span> zCoordinates = [<span class="hljs-number">3</span>, <span class="hljs-number">6</span>, <span class="hljs-number">1</span>, <span class="hljs-number">7</span>];

<span class="hljs-comment">// Create a zipped array of points</span>
<span class="hljs-keyword">const</span> points = zip(xCoordinates, yCoordinates, zCoordinates);

<span class="hljs-comment">// Use the zipped array of points</span>
<span class="hljs-built_in">console</span>.log(points);  <span class="hljs-comment">// [[1, 5, 3], [2, 6, 6], [3, 7, 1], [4, 8, 7]]</span>
</code></pre>
<p>In this example, the <code>zip</code> function is used to combine the <code>xCoordinates</code>, <code>yCoordinates</code>, and <code>zCoordinates</code> arrays into a single array of tuples.</p>
<h2 id="heading-8-modern-javascript-reactive-patterns">8 Modern Javascript Reactive Patterns</h2>
<p>Reactivity is essentially about how a system reacts to data changes and there are different types of reactivity. Our focus is on reactivity in terms of taking actions in response to data changes.</p>
<p>As a front-end engineer, I have to face it every single day. That’s because the browser itself is a fully asynchronous environment. Modern web interfaces must react quickly to user actions, and this includes updating the UI, sending network requests, managing navigation, and various other tasks.</p>
<p>While people often associate reactivity with frameworks, I believe that we can learn a lot by implementing it in pure Js. So, we are going to code patterns ourselves and also study some native browser APIs that are based on reactivity.</p>
<h3 id="heading-pubsub-or-publish-subscribe">PubSub or Publish-Subscribe</h3>
<p>PubSub is one of the most commonly used and fundamental reactivity patterns. The Publisher is responsible for notifying Subscribers about the updates and the Subscriber receives those updates and can react in response.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PubSub</span> </span>{
  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-built_in">this</span>.subscribers = {};
  }

  subscribe(event, callback) {
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.subscribers[event]) {
      <span class="hljs-built_in">this</span>.subscribers[event] = [];
    }

    <span class="hljs-built_in">this</span>.subscribers[event].push(callback);
  }

  <span class="hljs-comment">// Publish a message to all subscribers of a specific event</span>
  publish(event, data) {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.subscribers[event]) {
      <span class="hljs-built_in">this</span>.subscribers[event].forEach(<span class="hljs-function">(<span class="hljs-params">callback</span>) =&gt;</span> {
        callback(data);
      });
    }
  }
}

<span class="hljs-keyword">const</span> pubsub = <span class="hljs-keyword">new</span> PubSub();

pubsub.subscribe(<span class="hljs-string">'news'</span>, <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Subscriber 1 received news: <span class="hljs-subst">${message}</span>`</span>);
});

pubsub.subscribe(<span class="hljs-string">'news'</span>, <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Subscriber 2 received news: <span class="hljs-subst">${message}</span>`</span>);
});

<span class="hljs-comment">// Publish a message to the 'news' event</span>
pubsub.publish(<span class="hljs-string">'news'</span>, <span class="hljs-string">'Latest headlines: ...'</span>);

<span class="hljs-comment">// console logs are:</span>
<span class="hljs-comment">// Subscriber 1 received news: Latest headlines: ...</span>
<span class="hljs-comment">// Subscriber 2 received news: Latest headlines: ...</span>
</code></pre>
<p>One popular example of its usage is Redux. This popular state management library is based on this pattern (or more specifically, the Flux architecture). Thing works pretty simple in the context of Redux:</p>
<ul>
<li><p>Publisher: The store acts as the publisher. When an action is dispatched, the store notifies all the subscribed components about the state change.</p>
</li>
<li><p>Subscriber: Ui components in the application are the subscribers. They subscribe to the redux store and receive updates whenever the state changes.</p>
</li>
</ul>
<h3 id="heading-custom-events-as-a-browser-version-of-pubsub">Custom Events as a Browser Version of PubSub</h3>
<p>The browser offers an API for triggering or subscribing to custom events through the CustomEvent class and the dispatchEvent method. The latter provides us with the ability not only to trigger an event but also to attach any desired data to it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> customEvent = <span class="hljs-keyword">new</span> CustomEvent(<span class="hljs-string">'customEvent'</span>, {
  <span class="hljs-attr">detail</span>: <span class="hljs-string">'Custom event data'</span>, <span class="hljs-comment">// Attach desired data to the event</span>
});

<span class="hljs-keyword">const</span> element = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'.element-to-trigger-events'</span>);

element.addEventListener(<span class="hljs-string">'customEvent'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Subscriber 1 received custom event: <span class="hljs-subst">${event.detail}</span>`</span>);
});

element.addEventListener(<span class="hljs-string">'customEvent'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Subscriber 2 received custom event: <span class="hljs-subst">${event.detail}</span>`</span>);
});

<span class="hljs-comment">// Trigger the custom event</span>
element.dispatchEvent(customEvent);

<span class="hljs-comment">// console logs are:</span>
<span class="hljs-comment">// Subscriber 1 received custom event: Custom event data</span>
<span class="hljs-comment">// Subscriber 2 received custom event: Custom event data</span>
</code></pre>
<h3 id="heading-custom-event-targets">Custom Event Targets</h3>
<p>If you prefer not to dispatch an event globally on the window object, you can create your own event target.</p>
<p>By extending the native EventTarget class, you can dispatch events to the new instance. This ensures that your event is triggered only on the new class itself, avoiding global propagation. Moreover, you have the flexibility to attach handlers directly to this specific instance.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomEventTarget</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">EventTarget</span> </span>{
  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-built_in">super</span>();
  }

  <span class="hljs-comment">// Custom method to trigger events</span>
  triggerCustomEvent(eventName, eventData) {
    <span class="hljs-keyword">const</span> event = <span class="hljs-keyword">new</span> CustomEvent(eventName, { <span class="hljs-attr">detail</span>: eventData });
    <span class="hljs-built_in">this</span>.dispatchEvent(event);
  }
}

<span class="hljs-keyword">const</span> customTarget = <span class="hljs-keyword">new</span> CustomEventTarget();

<span class="hljs-comment">// Add an event listener to the custom event target</span>
customTarget.addEventListener(<span class="hljs-string">'customEvent'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Custom event received with data: <span class="hljs-subst">${event.detail}</span>`</span>);
});

<span class="hljs-comment">// Trigger a custom event</span>
customTarget.triggerCustomEvent(<span class="hljs-string">'customEvent'</span>, <span class="hljs-string">'Hello, custom event!'</span>);

<span class="hljs-comment">// console log is:</span>
<span class="hljs-comment">// Custom event received with data: Hello, custom event!</span>
</code></pre>
<h3 id="heading-observer">Observer</h3>
<p>The Observer pattern is really similar to PubSub. You subscribe to the subject and then it notifies its subscribers (Observers) about changes, allowing them to react accordingly. This pattern plays a significant role in building decoupled and flexible architecture.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Subject</span> </span>{
  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-built_in">this</span>.observers = [];
  }

  addObserver(observer) {
    <span class="hljs-built_in">this</span>.observers.push(observer);
  }

  <span class="hljs-comment">// Remove an observer from the list</span>
  removeObserver(observer) {
    <span class="hljs-keyword">const</span> index = <span class="hljs-built_in">this</span>.observers.indexOf(observer);

    <span class="hljs-keyword">if</span> (index !== <span class="hljs-number">-1</span>) {
      <span class="hljs-built_in">this</span>.observers.splice(index, <span class="hljs-number">1</span>);
    }
  }

  <span class="hljs-comment">// Notify all observers about changes</span>
  notify() {
    <span class="hljs-built_in">this</span>.observers.forEach(<span class="hljs-function">(<span class="hljs-params">observer</span>) =&gt;</span> {
      observer.update();
    });
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Observer</span> </span>{
  <span class="hljs-keyword">constructor</span>(name) {
    <span class="hljs-built_in">this</span>.name = name;
  }

  <span class="hljs-comment">// Update method called when notified</span>
  update() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> received an update.`</span>);
  }
}

<span class="hljs-keyword">const</span> subject = <span class="hljs-keyword">new</span> Subject();
<span class="hljs-keyword">const</span> observer1 = <span class="hljs-keyword">new</span> Observer(<span class="hljs-string">'Observer 1'</span>);
<span class="hljs-keyword">const</span> observer2 = <span class="hljs-keyword">new</span> Observer(<span class="hljs-string">'Observer 2'</span>);

<span class="hljs-comment">// Add observers to the subject</span>
subject.addObserver(observer1);
subject.addObserver(observer2);

<span class="hljs-comment">// Notify observers about changes</span>
subject.notify();

<span class="hljs-comment">// console logs are:</span>
<span class="hljs-comment">// Observer 1 received an update.</span>
<span class="hljs-comment">// Observer 2 received an update.</span>
</code></pre>
<h3 id="heading-reactive-properties-with-proxy">Reactive Properties With Proxy</h3>
<p>if you want to react to changes in objects, Proxy is a way to go. It lets us achieve reactivity when setting or getting values of the object field.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> person = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Pavel'</span>,
  <span class="hljs-attr">age</span>: <span class="hljs-number">22</span>,
};

<span class="hljs-keyword">const</span> reactivePerson = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(person, {
  <span class="hljs-comment">// Intercept set operation</span>
  set(target, key, value) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Setting <span class="hljs-subst">${key}</span> to <span class="hljs-subst">${value}</span>`</span>);
    target[key] = value;

    <span class="hljs-comment">// Indicates if setting value was successful</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  },
  <span class="hljs-comment">// Intercept get operation</span>
  get(target, key) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Getting <span class="hljs-subst">${key}</span>`</span>);

    <span class="hljs-keyword">return</span> target[key];
  },
});

reactivePerson.name = <span class="hljs-string">'Sergei'</span>; <span class="hljs-comment">// Setting name to Sergei</span>
<span class="hljs-built_in">console</span>.log(reactivePerson.name); <span class="hljs-comment">// Getting name: Sergei</span>

reactivePerson.age = <span class="hljs-number">23</span>; <span class="hljs-comment">// Setting age to 23</span>
<span class="hljs-built_in">console</span>.log(reactivePerson.age); <span class="hljs-comment">// Getting age: 23</span>
</code></pre>
<h3 id="heading-individual-object-properties-and-reactivity">Individual Object Properties and Reactivity</h3>
<p>If you don’t need to track all the fields in the objects, you can choose the specific one using Object.defineProperty or group of them with Object.defineProperties.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> person = {
  <span class="hljs-attr">_originalName</span>: <span class="hljs-string">'Pavel'</span>, <span class="hljs-comment">// private property</span>
}

<span class="hljs-built_in">Object</span>.defineProperty(person, <span class="hljs-string">'name'</span>, {
  get() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Getting property name'</span>)
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._originalName
  },
  set(value) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Setting property name to value <span class="hljs-subst">${value}</span>`</span>)
    <span class="hljs-built_in">this</span>._originalName = value
  },
})

<span class="hljs-built_in">console</span>.log(person.name) <span class="hljs-comment">// 'Getting property name' and 'Pavel'</span>
person.name = <span class="hljs-string">'Sergei'</span> <span class="hljs-comment">// Setting property name to value Sergei</span>
</code></pre>
<h3 id="heading-reactive-html-attributes-with-mutationobserver">Reactive HTML Attributes With MutationObserver</h3>
<p>One way to achieve reactivity in the DOM is by using MutationObserver. Its API allows us to observe changes in attributes and also in the text content of the target element and its children.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleMutations</span>(<span class="hljs-params">mutationsList, observer</span>) </span>{
  mutationsList.forEach(<span class="hljs-function">(<span class="hljs-params">mutation</span>) =&gt;</span> {
    <span class="hljs-comment">// An attribute of the observed element has changed</span>
    <span class="hljs-keyword">if</span> (mutation.type === <span class="hljs-string">'attributes'</span>) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Attribute '<span class="hljs-subst">${mutation.attributeName}</span>' changed to '<span class="hljs-subst">${mutation.target.getAttribute(mutation.attributeName)}</span>'`</span>);
    }
  });
}

<span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> MutationObserver(handleMutations);
<span class="hljs-keyword">const</span> targetElement = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.element-to-observe'</span>);

<span class="hljs-comment">// Start observing the target element</span>
observer.observe(targetElement, { <span class="hljs-attr">attributes</span>: <span class="hljs-literal">true</span> });
</code></pre>
<h3 id="heading-reactive-scrolling-with-intersectionobserver">Reactive Scrolling With IntersectionObserver</h3>
<p>The IntersectionObserver API enables reacting to the intersection of a target element with another element or the viewport area.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleIntersection</span>(<span class="hljs-params">entries, observer</span>) </span>{
  entries.forEach(<span class="hljs-function">(<span class="hljs-params">entry</span>) =&gt;</span> {
    <span class="hljs-comment">// The target element is in the viewport</span>
    <span class="hljs-keyword">if</span> (entry.isIntersecting) {
      entry.target.classList.add(<span class="hljs-string">'visible'</span>);
    } <span class="hljs-keyword">else</span> {
      entry.target.classList.remove(<span class="hljs-string">'visible'</span>);
    }
  });
}

<span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> IntersectionObserver(handleIntersection);
<span class="hljs-keyword">const</span> targetElement = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.element-to-observe'</span>);

<span class="hljs-comment">// Start observing the target element</span>
observer.observe(targetElement);
</code></pre>
<h2 id="heading-the-regular-expressions">The Regular Expressions</h2>
<p>You might see this written as regular expressions, regex, or RegExp, but all refer to the same thing.</p>
<p>Regex is a sequence of characters for matching a part of a string or the whole string. Matching strings with regular expressions might require more than just “characters“. Many times, you will need to use a special set of characters called “metacharacters“ and “quantifiers”.</p>
<p>Because regular expressions are a powerful tool, you can use them to do much more than just “matching strings“ when you combine regex with programming languages.</p>
<p>Almost all the main programming languages of the modern era have built-in support for regular expressions. Some programming languages might even have specific libraries that help you work more conveniently with regex.</p>
<p>Apart from using regular expressions in programming languages, other tools that let you use regular expressions are.</p>
<ul>
<li><p><strong>Text Editors and IDEs</strong>: These are for search and replacement in VS Code, Visual Studio, Notepad++, Sublime Text, and others.</p>
</li>
<li><p><strong>Browser Developer Tools</strong>: These are mostly in-browser search (with extensions or add-ons) and search within the developer tools.</p>
</li>
<li><p><strong>Database Tools</strong>: for data mining.</p>
</li>
<li><p><strong>RegEx Testers</strong>: you can paste in text and write the regular expressions to match them – which is a very good way to learn regular expressions. This book explores that option quite a bit.</p>
</li>
</ul>
<p>For more details, check out <a target="_blank" href="https://www.freecodecamp.org/news/regular-expressions-for-javascript-developers/">this article</a>.</p>
<h2 id="heading-stop-using-foreach-transform-your-code-with-forof-loop">Stop Using .forEach: Transform your code with for…of Loop</h2>
<p>In the realm of Javascript and Typescript, iterating over arrays is a common task. Many developers default to using <code>.forEach</code> for its simplicity and familiarity.</p>
<p>However, there is a more powerful and versatile alternative: the <code>for…of</code> loop.</p>
<h3 id="heading-understanding-the-basics-foreach-vs-forof"><strong>Understanding the Basics:</strong> <code>.forEach</code> vs. <code>for...of</code> 🔧</h3>
<p>The <code>.forEach</code> method is a straightforward way to iterate over an array. Here is a basic example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733126197882/7d4dad24-4393-476a-9510-e13249b714d3.webp" alt class="image--center mx-auto" /></p>
<p>The <code>for…of</code> loop, introduced in ES6, offers a more flexible way to iterate over iterable objects (including arrays):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733126296301/5cb11547-28fc-4ed1-ba9a-ff3c29651de4.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-why-prefer-forof">Why prefer <code>for…of</code>?</h3>
<p>While <code>.forEach</code> is concise and easy to use, <code>for…of</code> provides several advantages that can enhance your coding practice.</p>
<p><strong>Better Asynchronous Handling</strong></p>
<p>When dealing with asynchronous operations, <code>for…of</code> shines. The <code>.forEach</code> method doesn't work well with <code>async/await</code> because it doesn't handle promises natively. Consider the following example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733127317733/51dff63c-3088-4dce-872f-e2b26e9736cb.webp" alt class="image--center mx-auto" /></p>
<p>This code does not wait for each fetch operation to complete before starting the next one, which can lead to race operations and unexpected results.</p>
<p>The main downstream of iterating arrays with forEach loop is that it can be postponed until the previous call is fulfilled.</p>
<blockquote>
<p>This is very crucial is the real world when you work with the messive amount of assets that should be fetched one after another.</p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733128075827/81ad9315-bb60-4125-9c9b-803eb2ff7a84.webp" alt class="image--center mx-auto" /></p>
<p>In this example, each fetch operation waits for the previous one to complete, ensuring sequential execution and more predictable behavior.</p>
<p><strong>Breaking and Continuing Loops</strong></p>
<p>The <code>.forEach</code> method does not support the <code>continue</code> and <code>break</code> statements, which can limit its flexibility in certain scenarios.</p>
<p>Using <code>for…of</code> to break a loop</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733128410445/2ea8020c-07c8-4d16-8b33-78251415b2f0.webp" alt class="image--center mx-auto" /></p>
<p>Using <code>for…of</code> to continue a loop</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733128504716/24651b16-a459-4948-bf30-beee7c850720.webp" alt class="image--center mx-auto" /></p>
<p>This feature makes <code>for…of</code> more powerful and versatile for complex iteration logic.</p>
<h2 id="heading-making-good-use-of-console">Making Good Use of Console</h2>
<p><strong>Use case</strong>: Making good logging for debugging complex objects. Console methods like <code>console.table</code>, <code>console.group</code>, and <code>console.time</code> can provide more structured and informative debug information.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Basic logging</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Simple log'</span>);
<span class="hljs-built_in">console</span>.error(<span class="hljs-string">'This is an error'</span>);
<span class="hljs-built_in">console</span>.warn(<span class="hljs-string">'This is a warning'</span>);

<span class="hljs-comment">// Logging tabular data</span>
<span class="hljs-keyword">const</span> users = [
  { <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">30</span>, <span class="hljs-attr">city</span>: <span class="hljs-string">'New York'</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">'Jane'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span>, <span class="hljs-attr">city</span>: <span class="hljs-string">'San Francisco'</span> },
];
<span class="hljs-built_in">console</span>.table(users);

<span class="hljs-comment">// Grouping logs</span>
<span class="hljs-built_in">console</span>.group(<span class="hljs-string">'User Details'</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'User 1: John'</span>);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'User 2: Jane'</span>);
<span class="hljs-built_in">console</span>.groupEnd();

<span class="hljs-comment">// Timing code execution</span>
<span class="hljs-built_in">console</span>.time(<span class="hljs-string">'Timer'</span>);
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000</span>; i++) {
  <span class="hljs-comment">// Some heavy computation</span>
}
<span class="hljs-built_in">console</span>.timeEnd(<span class="hljs-string">'Timer'</span>);
</code></pre>
<p><strong>Why Use It</strong>: Enhances the visibility and organization of debugging information, making it easier to diagnose and fix issues. Propper use of console methods can significantly improve the efficiency of your debugging process by providing clear, organized, and detailed logs.</p>
<h2 id="heading-structured-cloning-with-structuredclone">Structured Cloning With <code>structuredClone()</code></h2>
<p>Deep clone objects using the new <code>structuredClone</code>. Unlike the traditional shallow copy, structured cloning creates a deep copy of the object, and ensures that nested objects are also copied. This method avoids the limitation of <code>JSON.parse(JSON.stringify(obj))</code>, which can not handle certain data types like functions, <code>undefined</code>, and circular references.</p>
<p><strong>Use case</strong>: Creating a deep copy of complex objects. This is useful when you need to duplicate objects for operations that should not mutate the original data.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> obj = { 
  <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, 
  <span class="hljs-attr">b</span>: { <span class="hljs-attr">c</span>: <span class="hljs-number">2</span> },
  <span class="hljs-attr">date</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
  <span class="hljs-attr">arr</span>: [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>],
  <span class="hljs-attr">nestedArr</span>: [{ <span class="hljs-attr">d</span>: <span class="hljs-number">4</span> }]
};
<span class="hljs-keyword">const</span> clonedObj = structuredClone(obj);

<span class="hljs-built_in">console</span>.log(clonedObj); 
<span class="hljs-comment">// { a: 1, b: { c: 2 }, date: 2023-06-08T00:00:00.000Z, arr: [1, 2, 3], nestedArr: [{ d: 4 }] }</span>
<span class="hljs-built_in">console</span>.log(clonedObj === obj); <span class="hljs-comment">// false</span>
<span class="hljs-built_in">console</span>.log(clonedObj.b === obj.b); <span class="hljs-comment">// false</span>
<span class="hljs-built_in">console</span>.log(clonedObj.date === obj.date); <span class="hljs-comment">// false</span>
<span class="hljs-built_in">console</span>.log(clonedObj.arr === obj.arr); <span class="hljs-comment">// false</span>
<span class="hljs-built_in">console</span>.log(clonedObj.nestedArr[<span class="hljs-number">0</span>] === obj.nestedArr[<span class="hljs-number">0</span>]); <span class="hljs-comment">// false</span>
</code></pre>
<p><strong>Why Use It</strong>: Provides a built-in, efficient way to perform deep cloning of objects, avoiding the pitfalls and complexities of manual deep copy implementations. This method is more reliable and handles complex data structures better than alternatives like <code>JSON.parse(JSON.stringify(obj))</code>.</p>
<h2 id="heading-self-invoking-functions">Self-Invoking Functions</h2>
<p>Self-invoking functions, also known as Immediately Invoked Function Expressions(IIEF), are executed immediately after they are created. They are useful for encapsulating code to avoid polluting the global scope, or in scenarios where immediate execution is needed for initialization logic.</p>
<pre><code class="lang-javascript">(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> privateVar = <span class="hljs-string">'This is private'</span>;
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Self-invoking function runs immediately'</span>);
  <span class="hljs-comment">// Initialization code here</span>
})();

<span class="hljs-comment">// Private variables are not accessible from outside</span>
<span class="hljs-comment">// console.log(privateVar); // ReferenceError: privateVar is not defined</span>
</code></pre>
<p><strong>Why Use It</strong>: Helps maintain clean code by avoiding global variables and executing initialization code without leaving traces in the global scope. This approach can prevent conflicts in larger codebases and ensure better encapsulation of functionality, improving code maintainability and avoiding side effects.</p>
<h2 id="heading-tagged-template-literals">Tagged Template Literals</h2>
<p>Tagged template literals allow you to customize the way template literals are processed. They are useful for creating specialized templates, such as for internationalization, sanitizing HTML, or generating dynamic SQL queries.</p>
<p><strong>Use Case</strong>: Sanitizing user input in HTML templates to prevent XSS attacks. This technique ensures that user-generated content is safely inserted into the DOM without executing any malicious scripts.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sanitize</span>(<span class="hljs-params">strings, ...values</span>) </span>{
  <span class="hljs-keyword">return</span> strings.reduce(<span class="hljs-function">(<span class="hljs-params">result, string, i</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> value = values[i - <span class="hljs-number">1</span>];
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value === <span class="hljs-string">'string'</span>) {
      value = value.replace(<span class="hljs-regexp">/&amp;/g</span>, <span class="hljs-string">'&amp;amp;'</span>)
                   .replace(<span class="hljs-regexp">/&lt;/g</span>, <span class="hljs-string">'&amp;lt;'</span>)
                   .replace(<span class="hljs-regexp">/&gt;/g</span>, <span class="hljs-string">'&amp;gt;'</span>)
                   .replace(<span class="hljs-regexp">/"/g</span>, <span class="hljs-string">'&amp;quot;'</span>)
                   .replace(<span class="hljs-regexp">/'/g</span>, <span class="hljs-string">'&amp;#39;'</span>);
    }
    <span class="hljs-keyword">return</span> result + value + string;
  });
}

<span class="hljs-keyword">const</span> userInput = <span class="hljs-string">'&lt;script&gt;alert("xss")&lt;/script&gt;'</span>;
<span class="hljs-keyword">const</span> message = sanitize<span class="hljs-string">`User input: <span class="hljs-subst">${userInput}</span>`</span>;
<span class="hljs-built_in">console</span>.log(message); <span class="hljs-comment">// User input: &amp;lt;script&amp;gt;alert("xss")&amp;lt;/script&amp;gt;</span>
</code></pre>
<p><strong>Why Use It</strong>: Provides a powerful mechanism to control and customize the output of template literals, enabling safer and more flexible template creation. Tagged template literals can be used to enforce security, format strings, and generate dynamic content, enhancing the robustness and versatility of your code.</p>
<h2 id="heading-12-javascript-web-apis-to-build-futuristic-websites-you-didnt-know">12 Javascript Web APIs to build Futuristic Websites You didn’t know</h2>
<p>With the rapidly changing technologies, developers are being provided with incredible new <strong>tools</strong> and <strong>APIs</strong>. However, it has been seen that out of the 100+ APIs, only 5% of them are actively used by developers.</p>
<p>Let’s take a look at some of the useful <strong>Web APIs</strong> that can help you skyrocket your website to noon.</p>
<p>Check out the list in <a target="_blank" href="https://blog.codingwinner.com/12-javascript-web-apis-to-build-futuristic-websites-you-didnt-know-8ba129027091">this article</a>.</p>
<h2 id="heading-the-mysteries-of-bind-call-and-apply">The Mysteries of <code>bind()</code>, <code>call()</code>, and <code>apply()</code></h2>
<p>Ever been deep in a Javascript rabbit hole and come across <code>bind()</code>, <code>call()</code>, and <code>apply()</code>? if you have ever scratched your head wondering what is the deal with these, you are not alone. Let’s chat about them like we are catching up over a cup of coffee.</p>
<p>Here is our line-up:</p>
<ul>
<li><p><strong>bind()</strong>: Think of it like giving a function a backpack filled with stuff(context), it will always carry around, no matter where it goes.</p>
</li>
<li><p><strong>call()</strong>: Imagine telling a function, “Hey, I need you to do this right now, with these items.“. You hand over the items one by one.</p>
</li>
<li><p><strong>apply()</strong>: Same as <code>call()</code>, but instead of handling items individually, you give a function a whole box (array) of items.</p>
</li>
</ul>
<h3 id="heading-bind-the-backpack-method">bind() - The backpack method</h3>
<p>Here is a simple way to understand <code>bind()</code>. Imagine you have got a little script that talks about someone.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">introduce</span>(<span class="hljs-params"></span>) </span>{
 <span class="hljs-keyword">return</span> <span class="hljs-string">`Hey, I’m <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>!`</span>;
}

<span class="hljs-keyword">const</span> person = { <span class="hljs-attr">name</span>: “Alex” };
<span class="hljs-keyword">const</span> sayHi = introduce.bind(person);

<span class="hljs-built_in">console</span>.log(sayHi()); <span class="hljs-comment">// “Hey, I’m Alex!”</span>
</code></pre>
<p>With <code>bind()</code>, it’s like giving the introduce function a backpack with a name tag that says “Alex.“</p>
<h3 id="heading-call-the-immediate-action">call() - The Immediate Action</h3>
<p><code>call()</code> is like being at a burger joint. You need to tell them what exactly toppings you want and expect the burger right away.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">orderBurger</span>(<span class="hljs-params">topping1, topping2</span>) </span>{
 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`I’d like a burger with <span class="hljs-subst">${topping1}</span> and <span class="hljs-subst">${topping2}</span>, please!`</span>);
}

orderBurger.call(<span class="hljs-literal">null</span>, “cheese”, “lettuce”); <span class="hljs-comment">// I’d like a burger with cheese and lettuce, please!</span>
</code></pre>
<p>See? You immediately tell the function what you want, and it serves it up right then</p>
<h3 id="heading-apply-the-boxed-lunch">apply() — The Boxed Lunch</h3>
<p><code>apply()</code> is pretty similar to <code>call()</code>, but instead of listing out toppings for your burger, you hand over the lunch box with everything inside.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makePizza</span>(<span class="hljs-params">topping1, topping2</span>) </span>{
 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Whipping up a pizza with <span class="hljs-subst">${topping1}</span> and <span class="hljs-subst">${topping2}</span>!`</span>);
}

<span class="hljs-keyword">const</span> toppings = [“pepperoni”, “mushrooms”];
makePizza.apply(<span class="hljs-literal">null</span>, toppings); <span class="hljs-comment">// Whipping up a pizza with pepperoni and mushrooms!</span>
</code></pre>
<p>You are still getting your pizza, but this time, all the ingredients came in a tidy little box.</p>
<h2 id="heading-explore-the-hidden-power-of-javascript-generators">Explore the hidden power of Javascript Generators</h2>
<p>Javascript Generators were first introduced in ES6. They are just normal functions with a little bit of strange behavior. They can stop their execution in the middle of the function and resume it further at the same point.</p>
<h3 id="heading-how-do-they-differ-from-normal-functions">How do they differ from normal functions?</h3>
<p>In the normal Javascript function, we expect the code inside will execute until we reach a return statement, an error, or the end of the function.</p>
<p>With a generator function, we are changing that behavior with the <code>yield</code> keyword. When we encounter <code>yield</code> in our function we are expressing that we would like to pause the execution, allowing us to get the value out or into the function.</p>
<h3 id="heading-syntax">Syntax</h3>
<p>They are declared like a normal function plus one <code>*</code> added to it. Here is the simplest example. A function that returns the numbers from 1 to 5.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> *<span class="hljs-title">example</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">yield</span> <span class="hljs-number">1</span>;
    <span class="hljs-keyword">yield</span> <span class="hljs-number">2</span>;
    <span class="hljs-keyword">yield</span> <span class="hljs-number">3</span>;
    <span class="hljs-keyword">yield</span> <span class="hljs-number">4</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-number">5</span>;
}
<span class="hljs-keyword">const</span> func = example();

<span class="hljs-built_in">console</span>.log(func.next()); <span class="hljs-comment">// { value:1, done:false }</span>
<span class="hljs-built_in">console</span>.log(func.next()); <span class="hljs-comment">// { value:2, done:false }</span>
<span class="hljs-built_in">console</span>.log(func.next()); <span class="hljs-comment">// { value:3, done:false }</span>
<span class="hljs-built_in">console</span>.log(func.next()); <span class="hljs-comment">// { value:4, done:false }</span>
<span class="hljs-built_in">console</span>.log(func.next()); <span class="hljs-comment">// { value:5, done:true }</span>
</code></pre>
<p>The most important thing about generators is the <code>yield</code> keyword. It is called an <code>yield expression</code>, because when we restart the generator, we will send the value back in, and whatever we send will be the computed result of that expression. To iterate on the generator we should use the method <code>.next()</code> over it. It actually returns the response of a type object with two properties: value and done. The value property is the <code>yield</code>ed-out value, and done is a boolean that indicates if the generator has completed or not.</p>
<h3 id="heading-what-are-the-advantages">What are the advantages?</h3>
<ul>
<li><p><strong>Memory Efficient</strong>: Generators are memory efficient, which means that the only values that are generated are those that are needed. With normal functions, values should be generated and kept to be used later on. Only those data and computations that are necessary, are used.</p>
</li>
<li><p><strong>Lazy Evaluation</strong>: The evaluation of an expression is not calculated until its value is needed. If it is not needed, it won’t exist. It is calculated on demand.</p>
</li>
<li><p><strong>Use Cases</strong>: You may ask yourself, why do I need that? Well, there are plenty of good practical examples of where and how we can use generators.</p>
</li>
<li><p><strong>Unique ID Generator</strong>: First the basic one is a ID generator. You should want everyone to have a unique ID so instead of using closure, you can do it with generators.</p>
<pre><code class="lang-javascript">  <span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">idGenerator</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>;
      <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
          <span class="hljs-keyword">yield</span> i++;
      }
  }

  <span class="hljs-keyword">const</span> ids = idGenerator();

  <span class="hljs-built_in">console</span>.log(ids.next().value); <span class="hljs-comment">// 1</span>
  <span class="hljs-built_in">console</span>.log(ids.next().value); <span class="hljs-comment">// 2</span>
  <span class="hljs-built_in">console</span>.log(ids.next().value); <span class="hljs-comment">// 3</span>
</code></pre>
</li>
</ul>
<h3 id="heading-using-with-promises">Using With Promises</h3>
<p>Here is an example of promise. The entire structure might look complicated, but if we focus on *main(), we can see that we are calling the API and getting results in data as if it were a synchronous call. There is only the addition of the <code>yield</code> in it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> URL = <span class="hljs-string">'https://someAPI?name='</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">callAPI</span>(<span class="hljs-params">name</span>) </span>{
    <span class="hljs-keyword">const</span> url = <span class="hljs-string">`<span class="hljs-subst">${URL}</span><span class="hljs-subst">${name}</span>`</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">resolve, reject</span>) </span>{
        $.ajax({
            url,
            <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>) </span>{
                resolve(data);
            }
        });
    });
}
<span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">yield</span> callAPI(<span class="hljs-string">'Svetli'</span>);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Data: '</span> + data);
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.error(err);
    }
}
<span class="hljs-keyword">const</span> it = main();
<span class="hljs-keyword">const</span> res = it.next();
res.value.then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> it.next(data));
</code></pre>
<p>If we want to write great code it should be easily maintained by other developers and generators give us exactly that: a clean and understandable structure that is easy to follow.</p>
<h2 id="heading-javascript-hidden-features">JavaScript Hidden Features</h2>
<h3 id="heading-advanced-usage-of-destructuring-assignment">Advanced Usage of <code>Destructuring</code> Assignment</h3>
<p><code>Destructuring</code> assignment is not just about simple variable extraction; it also has many powerful, advanced uses:</p>
<p><strong>1.1 Traditional way vs Destructuring</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way - verbose and repetitive</span>
<span class="hljs-keyword">const</span> user = {
  name: <span class="hljs-string">'Alice'</span>,
  age: <span class="hljs-number">25</span>,
  address: {
    city: <span class="hljs-string">'London'</span>,
    country: <span class="hljs-string">'England'</span>
  },
  hobbies: [<span class="hljs-string">'reading'</span>, <span class="hljs-string">'swimming'</span>, <span class="hljs-string">'coding'</span>]
};

<span class="hljs-keyword">const</span> name = user.name;
<span class="hljs-keyword">const</span> age = user.age;
<span class="hljs-keyword">const</span> city = user.address.city;
<span class="hljs-keyword">const</span> country = user.address.country;
<span class="hljs-keyword">const</span> firstHobby = user.hobbies[<span class="hljs-number">0</span>];
<span class="hljs-keyword">const</span> secondHobby = user.hobbies[<span class="hljs-number">1</span>];


<span class="hljs-comment">// Destructuring - concise and clear</span>
<span class="hljs-keyword">const</span> { 
  name, 
  age, 
  address: { city, country },
  hobbies: [firstHobby, secondHobby]
} = user;
</code></pre>
<p><strong>1.2 Function Parameter Destructuring</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createUser</span>(<span class="hljs-params">userInfo</span>) </span>{
 <span class="hljs-keyword">const</span> name = userInfo.name || <span class="hljs-string">'Anonymous'</span>;
 <span class="hljs-keyword">const</span> age = userInfo.age || <span class="hljs-number">18</span>;
 <span class="hljs-keyword">const</span> email = userInfo.email || <span class="hljs-string">'no-email@example.com'</span>;

 <span class="hljs-keyword">return</span> {
    name: name,
    age: age,
    email: email,
    id: <span class="hljs-built_in">Date</span>.now()
  };
}

<span class="hljs-comment">// Destructuring way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createUser</span>(<span class="hljs-params">{ 
  name = 'Anonymous', 
  age = 18, 
  email = 'no-email<span class="hljs-meta">@example</span>.com' 
} = {}</span>) </span>{
 <span class="hljs-keyword">return</span> { name, age, email, id: <span class="hljs-built_in">Date</span>.now() };
}
</code></pre>
<h3 id="heading-short-circuit-operators-and-nullish-coalescing">Short-Circuit Operators and Nullish Coalescing</h3>
<p>JavaScript logical operators are not only used for boolean operations but also for conditional assignments and setting default values.</p>
<p><strong>2.1 Nullish Coalescing Operator (??)</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserName</span>(<span class="hljs-params">user</span>) </span>{
  <span class="hljs-keyword">let</span> name;
  <span class="hljs-keyword">if</span> (user.name !== <span class="hljs-literal">null</span> &amp;&amp; user.name !== <span class="hljs-literal">undefined</span>) {
    name = user.name;
  } <span class="hljs-keyword">else</span> {
    name = <span class="hljs-string">'Guest'</span>;
  }
  <span class="hljs-keyword">return</span> name;
}

<span class="hljs-comment">// Using ?? operator</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserName</span>(<span class="hljs-params">user</span>) </span>{
  <span class="hljs-keyword">return</span> user.name ?? <span class="hljs-string">'Guest'</span>;
}
</code></pre>
<p><strong>2.2 Optional Chaining Operator (?.)</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way - requires multiple checks</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCity</span>(<span class="hljs-params">user</span>) </span>{
  <span class="hljs-keyword">if</span> (user &amp;&amp; user.address &amp;&amp; user.address.city) {
    <span class="hljs-keyword">return</span> user.address.city;
  }
  <span class="hljs-keyword">return</span> <span class="hljs-string">'Unknown'</span>;
}

<span class="hljs-comment">// Optional chaining syntax</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCity</span>(<span class="hljs-params">user</span>) </span>{
  <span class="hljs-keyword">return</span> user?.address?.city ?? <span class="hljs-string">'Unknown'</span>;
}
</code></pre>
<p><strong>2.3 Logical Assignment Operators</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way</span>
<span class="hljs-keyword">if</span> (!user.settings) {
  user.settings = {};
}
<span class="hljs-keyword">if</span> (user.settings.theme === <span class="hljs-literal">null</span> || user.settings.theme === <span class="hljs-literal">undefined</span>) {
  user.settings.theme = <span class="hljs-string">'light'</span>;
}

<span class="hljs-comment">// Logical assignment way</span>
user.settings ||= {};
user.settings.theme ??= <span class="hljs-string">'light'</span>;
</code></pre>
<h3 id="heading-modern-methods-for-arrays-and-objects">Modern Methods for Arrays and Objects</h3>
<p>ES6+ introduced array and object operations that significantly simplify data processing code.</p>
<p><strong>3.1 Array Deduplication and Filtering</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processUsers</span>(<span class="hljs-params">users</span>) </span>{
  <span class="hljs-keyword">const</span> uniqueUsers = [];
  <span class="hljs-keyword">const</span> activeAdults = [];

  <span class="hljs-comment">// Deduplication</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; users.length; i++) {
    <span class="hljs-keyword">let</span> isDuplicate = <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> j = <span class="hljs-number">0</span>; j &lt; uniqueUsers.length; j++) {
      <span class="hljs-keyword">if</span> (users[i].id === uniqueUsers[j].id) {
        isDuplicate = <span class="hljs-literal">true</span>;
        <span class="hljs-keyword">break</span>;
      }
    }
    <span class="hljs-keyword">if</span> (!isDuplicate) {
      uniqueUsers.push(users[i]);
    }
  }

  <span class="hljs-comment">// Filter active adults</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; uniqueUsers.length; i++) {
    <span class="hljs-keyword">if</span> (uniqueUsers[i].age &gt;= <span class="hljs-number">18</span> &amp;&amp; uniqueUsers[i].active) {
      activeAdults.push(uniqueUsers[i]);
    }
  }
  <span class="hljs-keyword">return</span> activeAdults;
}

<span class="hljs-comment">// Modern way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processUsers</span>(<span class="hljs-params">users</span>) </span>{
  <span class="hljs-keyword">return</span> [...new <span class="hljs-built_in">Set</span>(users.map(<span class="hljs-function"><span class="hljs-params">u</span> =&gt;</span> u.id))]
    .map(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> users.find(<span class="hljs-function"><span class="hljs-params">u</span> =&gt;</span> u.id === id))
    .filter(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> user.age &gt;= <span class="hljs-number">18</span> &amp;&amp; user.active);
}
</code></pre>
<p><strong>3.2 Dynamic Computation of Object Properties</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createConfig</span>(<span class="hljs-params"><span class="hljs-keyword">type</span>, value, isEnabled</span>) </span>{
  <span class="hljs-keyword">const</span> config = {};
  config[<span class="hljs-keyword">type</span> + <span class="hljs-string">'Setting'</span>] = value;
  config[<span class="hljs-keyword">type</span> + <span class="hljs-string">'Enabled'</span>] = isEnabled;
  config.timestamp = <span class="hljs-built_in">Date</span>.now();
  <span class="hljs-keyword">return</span> config;
}

<span class="hljs-comment">// Modern way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createConfig</span>(<span class="hljs-params"><span class="hljs-keyword">type</span>, value, isEnabled</span>) </span>{
  <span class="hljs-keyword">return</span> {
    [<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">type</span>}</span>Setting`</span>]: value,
    [<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">type</span>}</span>Enabled`</span>]: isEnabled,
    timestamp: <span class="hljs-built_in">Date</span>.now()
  };
}
</code></pre>
<h3 id="heading-advanced-usages-of-template-strings">Advanced Usages of Template Strings</h3>
<p>Template strings can do more than simple interpolation — they are useful in more complex scenarios.</p>
<p><strong>4.1 Tagged Template Functions</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way — complex HTML generation</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createUserCard</span>(<span class="hljs-params">user</span>) </span>{
  <span class="hljs-keyword">let</span> html = <span class="hljs-string">'&lt;div class="user-card"&gt;'</span>;
  html += <span class="hljs-string">'&lt;h3&gt;'</span> + escapeHtml(user.name) + <span class="hljs-string">'&lt;/h3&gt;'</span>;
  html += <span class="hljs-string">'&lt;p&gt;Age: '</span> + user.age + <span class="hljs-string">'&lt;/p&gt;'</span>;
  html += <span class="hljs-string">'&lt;p&gt;Email: '</span> + escapeHtml(user.email) + <span class="hljs-string">'&lt;/p&gt;'</span>;
  html += <span class="hljs-string">'&lt;/div&gt;'</span>;
  <span class="hljs-keyword">return</span> html;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">escapeHtml</span>(<span class="hljs-params">text</span>) </span>{
  <span class="hljs-keyword">const</span> div = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'div'</span>);
  div.textContent = text;
  <span class="hljs-keyword">return</span> div.innerHTML;
}

<span class="hljs-comment">// Tagged template way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">html</span>(<span class="hljs-params">strings, ...values</span>) </span>{
  <span class="hljs-keyword">return</span> strings.reduce(<span class="hljs-function">(<span class="hljs-params">result, <span class="hljs-built_in">string</span>, i</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> value = values[i] ? escapeHtml(values[i]) : <span class="hljs-string">''</span>;
    <span class="hljs-keyword">return</span> result + <span class="hljs-built_in">string</span> + value;
  }, <span class="hljs-string">''</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createUserCard</span>(<span class="hljs-params">user</span>) </span>{
  <span class="hljs-keyword">return</span> html`<span class="xml">
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"user-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span></span><span class="hljs-subst">${user.name}</span><span class="xml"><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>Age: </span><span class="hljs-subst">${user.age}</span><span class="xml"><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>Email: </span><span class="hljs-subst">${user.email}</span><span class="xml"><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>;
}
</code></pre>
<p><strong>4.2 Multiline Strings and Conditional Content</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateSQL</span>(<span class="hljs-params">table, conditions, orderBy</span>) </span>{
  <span class="hljs-keyword">let</span> sql = <span class="hljs-string">'SELECT * FROM '</span> + table;
  <span class="hljs-keyword">if</span> (conditions &amp;&amp; conditions.length &gt; <span class="hljs-number">0</span>) {
    sql += <span class="hljs-string">' WHERE '</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; conditions.length; i++) {
      <span class="hljs-keyword">if</span> (i &gt; <span class="hljs-number">0</span>) sql += <span class="hljs-string">' AND '</span>;
      sql += conditions[i];
    }
  }
  <span class="hljs-keyword">if</span> (orderBy) {
    sql += <span class="hljs-string">' ORDER BY '</span> + orderBy;
  }
  <span class="hljs-keyword">return</span> sql;
}

<span class="hljs-comment">// Template string way</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateSQL</span>(<span class="hljs-params">table, conditions = [], orderBy = ''</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-string">`
    SELECT * FROM <span class="hljs-subst">${table}</span>
    <span class="hljs-subst">${conditions.length ? <span class="hljs-string">`WHERE <span class="hljs-subst">${conditions.join(<span class="hljs-string">' AND '</span>)}</span>`</span> : <span class="hljs-string">''</span>}</span>
    <span class="hljs-subst">${orderBy ? <span class="hljs-string">`ORDER BY <span class="hljs-subst">${orderBy}</span>`</span> : <span class="hljs-string">''</span>}</span>
  `</span>.replace(<span class="hljs-regexp">/\s+/g</span>, <span class="hljs-string">' '</span>).trim();
}
</code></pre>
<h3 id="heading-functional-programming-techniques">Functional Programming Techniques</h3>
<p>Leveraging JavaScript’s functional programming features allows for writing more concise and maintainable code.</p>
<p><strong>5.1 Currying and Partial Application</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way — repetitive validation logic</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">validateEmail</span>(<span class="hljs-params">email</span>) </span>{
  <span class="hljs-keyword">const</span> emailRegex = <span class="hljs-regexp">/^[^\s@]+@[^\s@]+\.[^\s]+$/</span>;
  <span class="hljs-keyword">if</span> (!email) <span class="hljs-keyword">return</span> { valid: <span class="hljs-literal">false</span>, message: <span class="hljs-string">'Email is required'</span> };
  <span class="hljs-keyword">if</span> (!emailRegex.test(email)) <span class="hljs-keyword">return</span> { valid: <span class="hljs-literal">false</span>, message: <span class="hljs-string">'Invalid email format'</span> };
  <span class="hljs-keyword">return</span> { valid: <span class="hljs-literal">true</span> };
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">validateAge</span>(<span class="hljs-params">age</span>) </span>{
  <span class="hljs-keyword">if</span> (age == <span class="hljs-literal">null</span> || age == <span class="hljs-literal">undefined</span>) <span class="hljs-keyword">return</span> { valid: <span class="hljs-literal">false</span>, message: <span class="hljs-string">'Age is required'</span> };
  <span class="hljs-keyword">if</span> (age &lt; <span class="hljs-number">0</span> || age &gt; <span class="hljs-number">150</span>) <span class="hljs-keyword">return</span> { valid: <span class="hljs-literal">false</span>, message: <span class="hljs-string">'Invalid age range'</span> };
  <span class="hljs-keyword">return</span> { valid: <span class="hljs-literal">true</span> };
}

<span class="hljs-comment">// Functional way</span>
<span class="hljs-keyword">const</span> createValidator = <span class="hljs-function">(<span class="hljs-params">name, predicate, message</span>) =&gt;</span> value =&gt;
  value &amp;&amp; predicate(value) ? { valid: <span class="hljs-literal">true</span> } : { valid: <span class="hljs-literal">false</span>, message };

<span class="hljs-keyword">const</span> required = <span class="hljs-function"><span class="hljs-params">field</span> =&gt;</span> value =&gt;
  value ? { valid: <span class="hljs-literal">true</span> } : { valid: <span class="hljs-literal">false</span>, message: <span class="hljs-string">`<span class="hljs-subst">${field}</span> is required`</span> };

<span class="hljs-keyword">const</span> validateEmail = composeValidators(
  required(<span class="hljs-string">'Email'</span>),
  createValidator(<span class="hljs-string">'Email'</span>, <span class="hljs-function"><span class="hljs-params">email</span> =&gt;</span> /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email), <span class="hljs-string">'Invalid email format'</span>)
);

<span class="hljs-keyword">const</span> validateAge = composeValidators(
  required(<span class="hljs-string">'Age'</span>),
  createValidator(<span class="hljs-string">'Age'</span>, <span class="hljs-function"><span class="hljs-params">age</span> =&gt;</span> age &gt;= <span class="hljs-number">0</span> &amp;&amp; age &lt;= <span class="hljs-number">150</span>, <span class="hljs-string">'Invalid age range'</span>)
);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">composeValidators</span>(<span class="hljs-params">...validators</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-params">value</span> =&gt;</span> {
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> validator <span class="hljs-keyword">of</span> validators) {
      <span class="hljs-keyword">const</span> result = validator(value);
      <span class="hljs-keyword">if</span> (!result.valid) <span class="hljs-keyword">return</span> result;
    }
    <span class="hljs-keyword">return</span> { valid: <span class="hljs-literal">true</span> };
  };
}
</code></pre>
<p><strong>5.2 Piping and Function Composition</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Traditional way - nested calls</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processData</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-keyword">const</span> filtered = data.filter(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.active);
  <span class="hljs-keyword">const</span> mapped = filtered.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> ({
    ...item,
    displayName: item.firstName + <span class="hljs-string">' '</span> + item.lastName
  }));
  <span class="hljs-keyword">const</span> sorted = mapped.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> a.displayName.localeCompare(b.displayName));
  <span class="hljs-keyword">const</span> grouped = {};

  sorted.forEach(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> key = item.category;
    <span class="hljs-keyword">if</span> (!grouped[key]) grouped[key] = [];
    grouped[key].push(item);
  });

  <span class="hljs-keyword">return</span> grouped;
}

<span class="hljs-comment">// Functional way</span>
<span class="hljs-keyword">const</span> pipe = <span class="hljs-function">(<span class="hljs-params">...fns</span>) =&gt;</span> value =&gt; fns.reduce(<span class="hljs-function">(<span class="hljs-params">acc, fn</span>) =&gt;</span> fn(acc), value);

<span class="hljs-keyword">const</span> filterActive = <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> data.filter(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.active);
<span class="hljs-keyword">const</span> addDisplayName = <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> data.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> ({
  ...item,
  displayName: <span class="hljs-string">`<span class="hljs-subst">${item.firstName}</span> <span class="hljs-subst">${item.lastName}</span>`</span>
}));
<span class="hljs-keyword">const</span> sortByName = <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> [...data].sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> a.displayName.localeCompare(b.displayName));
<span class="hljs-keyword">const</span> groupByCategory = <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> data.reduce(<span class="hljs-function">(<span class="hljs-params">acc, item</span>) =&gt;</span> {
  (acc[item.category] ||= []).push(item);
  <span class="hljs-keyword">return</span> acc;
}, {});

<span class="hljs-keyword">const</span> processData = pipe(
  filterActive,
  addDisplayName,
  sortByName,
  groupByCategory
);
</code></pre>
<p>These techniques can reduce code size by 30-60%, but more importantly, they make code cleaner, more readable, and easier to maintain. Applying these features reasonably in real projects will greatly improve development efficiency and code quality.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>JavaScript is a language rich with features that can help you write cleaner, more efficient code. By mastering these advanced concepts, you can improve your productivity and enhance the readability of your code.</p>
<p>Happy coding !!!</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://medium.com/version-1/cloning-an-object-in-javascript-shallow-copy-vs-deep-copy-fa8acd6681e9">https://medium.com/version-1/cloning-an-object-in-javascript-shallow-copy-vs-deep-copy-fa8acd6681e9</a></p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/javascript-let-and-const-hoisting/">https://www.freecodecamp.org/news/javascript-let-and-const-hoisting/</a></p>
<p><a target="_blank" href="https://blog.jetbrains.com/webstorm/2024/10/javascript-best-practices-2024/">https://blog.jetbrains.com/webstorm/2024/10/javascript-best-practices-2024/</a></p>
<p><a target="_blank" href="https://www.paulsblog.dev/advanced-javascript-functions-to-improve-code-quality/">https://www.paulsblog.dev/advanced-javascript-functions-to-improve-code-quality/</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/8-modern-javascript-reactive-patterns-0b5698fdb46e">https://levelup.gitconnected.com/8-modern-javascript-reactive-patterns-0b5698fdb46e</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/stop-using-foreach-transform-your-code-with-for-of-loop-advanced-javascript-5d9d61a95740">https://levelup.gitconnected.com/stop-using-foreach-transform-your-code-with-for-of-loop-advanced-javascript-5d9d61a95740</a></p>
<p><a target="_blank" href="https://medium.com/@bjprajapati381/10-advanced-javascript-tricks-you-dont-know-f1929e40703d">https://medium.com/@bjprajapati381/10-advanced-javascript-tricks-you-dont-know-f1929e40703d</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/8-advanced-javascript-interview-questions-for-senior-roles-c59e1b0f83e1">https://levelup.gitconnected.com/8-advanced-javascript-interview-questions-for-senior-roles-c59e1b0f83e1</a></p>
<p><a target="_blank" href="https://medium.com/from-code-to-beyond/explore-the-hidden-power-of-javascript-generators-43c9dde37486">https://medium.com/from-code-to-beyond/explore-the-hidden-power-of-javascript-generators-43c9dde37486</a></p>
<p><a target="_blank" href="https://medium.com/@obrm770/javascript-under-the-hood-8cec84bbfd64">https://medium.com/@obrm770/javascript-under-the-hood-8cec84bbfd64</a></p>
<p><a target="_blank" href="https://medium.com/@letscodefuture/mastering-javascript-advanced-oop-concepts-and-interview-questions-933027b1d0cb">https://medium.com/@letscodefuture/mastering-javascript-advanced-oop-concepts-and-interview-questions-933027b1d0cb</a></p>
<p><a target="_blank" href="https://blog.stackademic.com/9-must-know-advanced-uses-of-promises-a6d1ab195dfc">https://blog.stackademic.com/9-must-know-advanced-uses-of-promises-a6d1ab195dfc</a></p>
<p><a target="_blank" href="https://medium.com/illumination/how-to-cancel-javascript-api-request-with-abortcontroller-c4a3280691a2">https://medium.com/illumination/how-to-cancel-javascript-api-request-with-abortcontroller-c4a3280691a2</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/object-freeze-vs-object-seal-vs-object-preventextensions-in-javascript-7e76bbec456c">https://javascript.plainenglish.io/object-freeze-vs-object-seal-vs-object-preventextensions-in-javascript-7e76bbec456c</a></p>
<p><a target="_blank" href="https://habtesoft.medium.com/7-advanced-javascript-object-techniques-you-need-to-know-854142fe30b4">https://habtesoft.medium.com/7-advanced-javascript-object-techniques-you-need-to-know-854142fe30b4</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/javascript-hidden-features-5-methods-to-reduce-your-code-by-50-f01302427e5e">https://javascript.plainenglish.io/javascript-hidden-features-5-methods-to-reduce-your-code-by-50-f01302427e5e</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/the-javascript-function-secret-that-professional-developers-know-but-never-explain-to-beginners-2f77729cb6e2">https://javascript.plainenglish.io/the-javascript-function-secret-that-professional-developers-know-but-never-explain-to-beginners-2f77729cb6e2</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/why-javascript-is-single-threaded-and-why-thats-a-good-thing-ecd34c1af2cb">https://javascript.plainenglish.io/why-javascript-is-single-threaded-and-why-thats-a-good-thing-ecd34c1af2cb</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/5-async-await-secrets-that-professional-javascript-developers-use-but-never-document-66ebea11d0e1">https://javascript.plainenglish.io/5-async-await-secrets-that-professional-javascript-developers-use-but-never-document-66ebea11d0e1</a></p>
<p><a target="_blank" href="https://medium.com/the-syntax-diaries/stop-writing-async-await-like-this-heres-what-senior-engineers-do-537f8d5be57e">https://medium.com/the-syntax-diaries/stop-writing-async-await-like-this-heres-what-senior-engineers-do-537f8d5be57e</a></p>
]]></content:encoded></item><item><title><![CDATA[🔥TypeScript Handbook]]></title><description><![CDATA[TypeScript is a widely used, open-source programming language that is perfect for modern development. With its advanced type system, TypeScript allows developers to write more robust, maintainable, and scalable code. But, to truly harness the power o...]]></description><link>https://blog.tuanhadev.tech/mastering-typescript</link><guid isPermaLink="true">https://blog.tuanhadev.tech/mastering-typescript</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[TypeScript Best Practices]]></category><category><![CDATA[TypeScript tips]]></category><category><![CDATA[Advanced TypeScript Techniques]]></category><category><![CDATA[TypeSafety]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Sat, 26 Oct 2024 10:53:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/BplhhW_JyhQ/upload/66d4f3c1486876595d74a670470598c6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>TypeScript</strong> is a widely used, open-source programming language that is perfect for modern development. With its advanced type system, TypeScript allows developers to write more robust, maintainable, and scalable code. But, to truly harness the power of TypeScript and build high-quality projects, it’s essential to understand and follow best practices. This article will walk through the Advanced Typescript concepts and capabilities. Whether you are just starting or you are an experienced Typescript developer, this article will provide valuable insights and tips to help you write clean, efficient code.</p>
<p>So, grab a cup of coffee, and let’s get started on our journey to mastering TypeScript!</p>
<h1 id="heading-advanced-typescript-cheat-sheet">Advanced Typescript cheat sheet</h1>
<p>TypeScript is a simple language that allows developers to express types in terms of other types. However, while performing the basic tasks, having a profound understanding of how TypeScript works is critical for unlocking its advanced functionality.</p>
<p>As we learn more about TypeScript, we can utilize this knowledge to write cleaner and testable code. In this section, we are combining all the basic concepts of TypeScript and its advanced features in a single cheatsheet. So here we go.</p>
<h2 id="heading-typescript-concepts-misunderstood">TypeScript Concepts Misunderstood</h2>
<h3 id="heading-types-vs-interfaces-in-typescript">Types vs interfaces in TypeScript</h3>
<p>We have two options for defining types in TypeScript: types and interfaces. One of the most frequently asked questions about whether we should use interfaces or types.</p>
<p>The answer to this question, like many programming questions, is that it depends. In some cases, one has a clear advantage over the other, but in many cases, they are interchangeable.</p>
<p><strong>Types and type aliases</strong></p>
<p><code>type</code> is a keyword in TypeScript that we can use to define the shape of data. The basic types in TypeScript include:</p>
<ul>
<li><p>String</p>
</li>
<li><p>Boolean</p>
</li>
<li><p>Number</p>
</li>
<li><p>Array</p>
</li>
<li><p><a target="_blank" href="https://blog.logrocket.com/use-cases-named-tuples-typescript/">Tupl</a><a target="_blank" href="https://blog.logrocket.com/typescript-string-enums-guide/">e</a></p>
</li>
<li><p><a target="_blank" href="https://blog.logrocket.com/typescript-string-enums-guide/">En</a><a target="_blank" href="https://blog.logrocket.com/use-cases-named-tuples-typescript/">um</a></p>
</li>
<li><p>Advanced types</p>
</li>
</ul>
<p>Each has unique features and purposes, allowing developers to choose the appropriate one for their particular use case.</p>
<p>Type aliases in TypeScript mean “a name for any type“. They provide a way of creating new names for existing types. Type aliases don’t define new types; instead, they provide an alternative name for an existing type.</p>
<p>Type aliases can be created using the type keyword, referring to any valid TypeScript type, including primitive types:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> MyNumber = <span class="hljs-built_in">number</span>;
<span class="hljs-keyword">type</span> User = {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p><strong>Interfaces in TypeScript</strong></p>
<p>In Typescript, an interface defines a contract to which an object must adhere. Below is an example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Client { 
    name: <span class="hljs-built_in">string</span>; 
    address: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p><strong>Differences between types and interfaces</strong></p>
<ul>
<li><p><strong>Primitive Types</strong>: Primitive types are built-in types in Typescript. They include <code>number</code>, <code>string</code>, <code>boolean</code>, <code>null</code>, and <code>undefined</code> types. We can define a type for a primitive type, but we can’t use an interface to alias a primitive type.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">type</span> Address = <span class="hljs-built_in">string</span>;
  <span class="hljs-keyword">type</span> NullOrUndefined = <span class="hljs-literal">null</span> | <span class="hljs-literal">undefined</span>;
</code></pre>
</li>
<li><p><strong>Union types</strong>: Union types allow us to describe values that can be one of several types and create unions of various primitive, literal, or complex types. Union types can only be defined using type. There is no equivalent to a union type in an interface. But it’s possible to create a new union type from two interfaces.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">type</span> Transport = <span class="hljs-string">'Bus'</span> | <span class="hljs-string">'Car'</span> | <span class="hljs-string">'Bike'</span> | <span class="hljs-string">'Walk'</span>;
  <span class="hljs-keyword">interface</span> CarBattery {
    power: <span class="hljs-built_in">number</span>;
  }
  <span class="hljs-keyword">interface</span> Engine {
    <span class="hljs-keyword">type</span>: <span class="hljs-built_in">string</span>;
  }
  <span class="hljs-keyword">type</span> HybridCar = Engine | CarBattery;
</code></pre>
</li>
<li><p><strong>Function types:</strong> In TypeScript, a function type represents a function’s type signature. Using a type alias, we need to specify the parameters and the return type to define a function type:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">type</span> AddFn =  <span class="hljs-function">(<span class="hljs-params">num1: <span class="hljs-built_in">number</span>, num2:<span class="hljs-built_in">number</span></span>) =&gt;</span> <span class="hljs-built_in">number</span>;
  <span class="hljs-keyword">interface</span> IAdd {
     (num1: <span class="hljs-built_in">number</span>, num2:<span class="hljs-built_in">number</span>): <span class="hljs-built_in">number</span>;
  }
</code></pre>
<p>  Both type and interface similarly define function types, except for a subtle syntax difference of interface using “:” vs “=&gt;” when using type. Type is preferred because it’s short and thus easier to read.</p>
</li>
<li><p><strong>Declaration merging:</strong> Declaration merging is a feature that is exclusive to interfaces. With declaration merging, we can define interfaces multiple times, and the TypeScript compiler will automatically merge these definitions into a single interface definition.</p>
<p>  In the following example, the two Client interface definitions are merged into one by the TypeScript compiler, and we have two properties when using the Client Interface.</p>
<pre><code class="lang-javascript">  interface Client { 
      <span class="hljs-attr">name</span>: string; 
  }

  interface Client {
      <span class="hljs-attr">age</span>: number;
  }

  <span class="hljs-keyword">const</span> harry: Client = {
      <span class="hljs-attr">name</span>: <span class="hljs-string">'Harry'</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">41</span>
  }
</code></pre>
<p>  Type aliases can’t be merged in the same way if you try to define the Client type more than once, as, in the above example, the error will be thrown.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728123067699/d694b8de-c550-495c-887e-c91df7cdf0f7.avif" alt class="image--center mx-auto" /></p>
<p>  When used in the right places, definition merging can be very useful. One common use case for declaration merging is to extend the third-party type definition to fit the particular project's needs.</p>
<p>  If you need to merge declarations, interfaces are the way to go.</p>
</li>
<li><p><strong>Extends vs. intersection</strong>: An interface can extend one or multiple interfaces. Using the <code>extend</code> keyword, an interface can inherit all the properties and methods of an existing interface while also adding new properties.</p>
<p>  For example, we can create a <code>VipClient</code> interface by extending the <code>Client</code> interface:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">interface</span> VIPClient <span class="hljs-keyword">extends</span> Client {
      benefits: <span class="hljs-built_in">string</span>[]
  }
</code></pre>
<p>  To achieve a similar result for types, we need to use an intersection operator:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">type</span> VIPClient = Client &amp; {benefits: <span class="hljs-built_in">string</span>[]}; <span class="hljs-comment">// Client is a type</span>
</code></pre>
<p>  You can extend an interface from a type alias with static known members:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">type</span> Client = {
      name: <span class="hljs-built_in">string</span>;
  };

  <span class="hljs-keyword">interface</span> VIPClient <span class="hljs-keyword">extends</span> Client {
      benefits: <span class="hljs-built_in">string</span>[]
  }
</code></pre>
</li>
<li><p><strong>Handling conflicts when extending:</strong> Another difference between types and interfaces is how conflicts are handled when you try to extend from one with the same property.</p>
<p>  When extending interfaces, the same property isn’t allowed, as in the example below:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">interface</span> Person {
    getPermission: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">string</span>;
  }

  <span class="hljs-keyword">interface</span> Staff <span class="hljs-keyword">extends</span> Person {
     getPermission: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">string</span>[];
  }
</code></pre>
<p>  An error is thrown because a conflict is detected.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728124610248/4e06cbcd-b24e-4b9a-a60e-7783a0999afc.avif" alt class="image--center mx-auto" /></p>
<p>  Type aliases handle conflicts differently. In the case of type aliases extending another type with the same property key, it will automatically merge all properties instead of throwing an error.</p>
<p>  In the following example, the intersection operator merges the method signatures of the two <code>getPermission</code> declarations and a <code>typeof</code> operator is used to narrow down the union type parameter so that we can get the return value in a type-safe way:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">type</span> Person = {
    getPermission: <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">string</span>;
  };

  <span class="hljs-keyword">type</span> Staff = Person &amp; {
     getPermission: <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span>[]</span>) =&gt;</span> <span class="hljs-built_in">string</span>[];
  };

  <span class="hljs-keyword">const</span> AdminStaff: Staff = {
    getPermission: <span class="hljs-function">(<span class="hljs-params">id: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">string</span>[]</span>) =&gt;</span>{
      <span class="hljs-keyword">return</span> (<span class="hljs-keyword">typeof</span> id === <span class="hljs-string">'string'</span>?  <span class="hljs-string">'admin'</span> : [<span class="hljs-string">'admin'</span>]) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>[] &amp; <span class="hljs-built_in">string</span>;
    }
  }
</code></pre>
<p>  It is important to note that the type intersection of two properties may produce unexpected results. In the example below, the <code>name</code> property for the extended type <code>Staff</code> becomes <code>never</code>, since it can’t be both <code>number</code> and <code>string</code> at the same time:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">type</span> Person = {
      name: <span class="hljs-built_in">string</span>
  };

  <span class="hljs-keyword">type</span> Staff = person &amp; {
      name: <span class="hljs-built_in">number</span>
  };
  <span class="hljs-comment">// error: Type 'string' is not assignable to type 'never'.(2322)</span>
  <span class="hljs-keyword">const</span> Harry: Staff = { name: <span class="hljs-string">'Harry'</span> };
</code></pre>
</li>
<li><p><strong>Prefer extends over an intersection:</strong> Often, when using an interface, TypeScript will generally do a better job displaying the shape of the interface in error messages, tooltips, and IDEs. It is also much easier to read, no matter how many types you combine or extend.</p>
<p>  Compare that to the type alias that uses the intersection of two or more types like <code>type A = B &amp; C;</code>, and you then type to use that alias in another intersection like <code>type X = A &amp; D;</code>, TypeScript can struggle to display the structure of the combined type, making it harder to understand the shape of the type from the error messages.</p>
<p>  TypeScript caches the results of the evaluated relationship between interfaces, like whether one interface extends another or if two interfaces are compatible. This approach improves the overall performance when the same relationship is referenced in the future.</p>
<p>  In contrast, when working with intersections, TypeScript does not cache these relationships. Every time a type intersection is used, TypeScript has to re-evaluate the entire intersection, which can lead to efficiency concerns.</p>
<p>  For these reasons, it is advisable to use interface extends instead of relying on type intersections.</p>
</li>
<li><p><strong>Advanced type features</strong>: TypeScript provides a wide range of advanced type features that can’t be found in interfaces. Some of the unique features in TypeScript include:</p>
<ul>
<li><p>Type inferences: Can infer the type of variables and functions based on their usage. This reduces the amount of code and improves readability</p>
</li>
<li><p>Conditional types: Allow us to create complex type expressions with conditional behaviors that depend on other types</p>
</li>
<li><p><a target="_blank" href="https://blog.logrocket.com/how-to-use-type-guards-typescript/">Type guards</a>: Used to write sophisticated control flow based on the type of variable.</p>
</li>
<li><p>Mapped types: Transforms an existing object type into a new type</p>
</li>
<li><p>Utility types: A set of out-of-the-box utilities that help to manipulate types</p>
</li>
</ul>
</li>
</ul>
<p>    TypeScript’s typing system constantly evolves with every new release, making it a complex and powerful toolbox. The impressive typing system is one of the main reasons many developers prefer to use TypeScript.</p>
<p><strong>When to use types vs. interfaces</strong></p>
<p>In many cases, they can be used interchangeably depending on personal preference. But we should use type aliases in the following use cases:</p>
<ul>
<li><p>To create a new name for a primitive type</p>
</li>
<li><p>To define a union type, a tuple type, a function type, or another more complex type.</p>
</li>
<li><p>To overload functions.</p>
</li>
<li><p>To use mapped types, conditional types, type guards, or other advanced type features.</p>
</li>
</ul>
<p>Compared with interfaces, types are more expressive. Many advanced type features are unavailable in interfaces, and those features continue to grow as TypeScript is involved.</p>
<h3 id="heading-type-safety-in-typescript-unknown-vs-any">Type safety in TypeScript - Unknown vs any</h3>
<p>In Typescript, two types that are often used are <code>any</code> vs <code>unknown</code>. They might look the same at first, but they are used for different things.</p>
<p><strong>Exploring unknown</strong></p>
<p>The <code>unknow</code> type is a safer choice than <code>any</code>. When a variable is of type unknown, TypeScript makes you check the type before you can use the variable. This makes developers clearly state their assumptions, which helps to avoid errors when the code is running.</p>
<p>Think about a situation when you are using the data from an API, and you are not sure what the data looks like. Using an unknown type helps you deal with uncertainty in a safe way.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processData</span>(<span class="hljs-params">data: unknown</span>): <span class="hljs-title">string</span> </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> data === <span class="hljs-string">'string'</span>) {
    <span class="hljs-keyword">return</span> data.toUpperCase();
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Handle other cases appropriately</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Invalid data"</span>;
  }
}

<span class="hljs-comment">// No compilation error</span>
<span class="hljs-keyword">const</span> result = processData(<span class="hljs-string">"Hello, TypeScript!"</span>);
</code></pre>
<p>In simpler terms, using <code>unknown</code> type ensures you double-check what kind of data you have before you do anything with it. This helps prevent mistakes that could happen when the program is running.</p>
<p><strong>Exploring any</strong></p>
<p>On the other hand, <code>any</code> is the most easy-going type in Typescript. It skips type-checking, letting variables of this type be set to anything without making the code fail to compile. While this freedom can be handy, it means you lose the advantages of static typing.</p>
<p>Think about a situation where you want as much flexibility as possible, and you are sure that your code is type-safe.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processDynamicData</span>(<span class="hljs-params">data: <span class="hljs-built_in">any</span></span>): <span class="hljs-title">string</span> </span>{
  <span class="hljs-comment">// No compilation error</span>
  <span class="hljs-keyword">return</span> data.toUpperCase(); 
}

<span class="hljs-comment">// No compilation error, works as expected</span>
<span class="hljs-keyword">const</span> result1 = processDynamicData(<span class="hljs-string">"Hello, TypeScript!"</span>); 
<span class="hljs-built_in">console</span>.log(result1); <span class="hljs-comment">// Outputs: "HELLO, TYPESCRIPT!"</span>

<span class="hljs-comment">// No compilation error, but will cause a runtime error</span>
<span class="hljs-keyword">const</span> result2 = processDynamicData(<span class="hljs-number">12345</span>); 
<span class="hljs-built_in">console</span>.log(result2); <span class="hljs-comment">// Error: data.toUpperCase is not a function</span>
</code></pre>
<p>In simpler terms, using any means, you don’t have to check the type of data, but it can cause problems if the data type is not what you expected.</p>
<p><strong>When to use</strong></p>
<p>When using TypeScript, you can use <code>unknown</code> when you want to be very careful with your code and make sure everything is the right type. <code>any</code> is used when you want to be more flexible, but this can make your code less safe. You should think carefully about which one to use, depending on what your code needs and how confident you are about the types and safety of your code.</p>
<h3 id="heading-the-differences-between-object-and-object-in-typescript">The Differences Between <code>Object</code>, <code>{}</code>, and <code>object</code> in Typescript</h3>
<p>In Typescript, when we want to define an object type, there are several concise ways, such as <code>Object</code>, <code>{}</code>, and <code>object</code>. What are the differences between them?</p>
<p><strong>Object (uppercased)</strong></p>
<p>Object (uppercased) describes properties common to all JavaScript objects. It is defined in the <a target="_blank" href="http://lib.es"><em>lib.es</em></a><a target="_blank" href="https://github.com/microsoft/TypeScript/blob/main/src/lib/es5.d.ts?utm_source=webdeveloper.beehiiv.com&amp;utm_medium=newsletter&amp;utm_campaign=the-differences-between-object-and-object-in-typescript#L105"><em>5.d.ts</em></a> file that comes with the TypeScript library.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728378791860/84ec2d92-3d89-437f-ac01-a897f3291139.png" alt class="image--center mx-auto" /></p>
<p>As you can see, it includes some common properties like <code>toString()</code>, <code>valueOf()</code>, and so on.</p>
<p>Because it emphasizes only those properties that are common to JavaScript objects. So you can assign boxable objects like <code>string</code>, <code>boolean</code>, <code>number</code>, <code>bigint</code>, <code>symbol</code> to it, but not the other way around.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728379216119/7b25e114-b78c-4fa6-aab1-11eba52ad65d.jpeg" alt class="image--center mx-auto" /></p>
<p><strong>{}</strong></p>
<p><code>{}</code> describes an object that has no members on its own, which means Typescript will complain if you try to access its property members.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728379346633/fe7cccd4-ad81-4110-9834-bae568a53b97.jpeg" alt class="image--center mx-auto" /></p>
<p>From the code example above, we can see that <code>{}</code> and <code>Object</code> (uppercased) have the same features. That is, it can only access those properties that are common (even if the JavaScript code logic is correct), and all boxable objects can be assigned to it, etc.</p>
<p>This is because the <code>{}</code> type can access those common properties through the prototype chain, it also has no own properties. So it behaves the same as the <code>Object</code> (uppercased) type. But they represent different concepts.</p>
<p><strong>object (lowercased)</strong></p>
<p><code>object</code> (lowercased) means any no-primitive type, which is expressed in code like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> PrimitiveType =
  | <span class="hljs-literal">undefined</span>
  | <span class="hljs-literal">null</span>
  | <span class="hljs-built_in">string</span>
  | <span class="hljs-built_in">number</span>
  | <span class="hljs-built_in">boolean</span>
  | bigint
  | symbol;

<span class="hljs-keyword">type</span> NonPrimitiveType = <span class="hljs-built_in">object</span>;
</code></pre>
<p>This means that all primitive types are not assignable to it, and vice versa:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728380003693/3b4593f1-f3cb-4057-b31e-cd779e43e5db.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-typescript-advanced-concepts">TypeScript Advanced Concepts</h2>
<h3 id="heading-leverage-strict-typing-options">Leverage Strict Typing Options</h3>
<p>TypeScript’s compiler options allow you to enforce stricter type-checking rules. Setting <code>"strict": true</code> in your <code>tsconfig.json</code> is a great starting point, but consider enabling additional options like:</p>
<ul>
<li><p><strong>"noImplicitAny"</strong>: Avoids using the any type unintentionally.</p>
</li>
<li><p><strong>"strictNullChecks"</strong>: Ensures variables cannot be null or undefined unless explicitly allowed.</p>
</li>
<li><p><strong>"strictFunctionTypes"</strong>: Enforces correct function type inference, preventing subtle bugs.</p>
</li>
</ul>
<p>Stricter typing often reveals hidden bugs and makes your codebase more reliable.</p>
<h3 id="heading-using-never-type">Using <code>never</code> type</h3>
<p>In Typescript, <code>never</code> is a special type that represents the value that will never occur. It’s used to indicate that a function will not return normally, but will instead throw an error. This is a great way to identify to other developers and the compiler that a function can be used in certain ways, which can help to catch potential bugs.</p>
<p>For example, consider the following function that throws an error if the input is 0:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">divide</span>(<span class="hljs-params">numerator: <span class="hljs-built_in">number</span>, denominator: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">number</span> </span>{
 <span class="hljs-keyword">if</span> (denominator === <span class="hljs-number">0</span>) {
 <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Cannot divide by zero"</span>);
 }
 <span class="hljs-keyword">return</span> numerator / denominator;
}
</code></pre>
<p>Here, the function divide is declared to return a number, but if the denominator is zero, it will throw an error. To indicate that this function will not return normally in this case, you can use <code>never</code> as a return type:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">divide</span>(<span class="hljs-params">numerator: <span class="hljs-built_in">number</span>, denominator: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">number</span> | <span class="hljs-title">never</span> </span>{
 <span class="hljs-keyword">if</span> (denominator === <span class="hljs-number">0</span>) {
   <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Cannot divide by zero"</span>);
 }
   <span class="hljs-keyword">return</span> numerator / denominator;
}
</code></pre>
<h3 id="heading-using-enums">Using Enums</h3>
<p>Enums, short for enumerations, are a way to define a set of named constants in Typescript. They can be used to create a more readable and maintainable code by giving a meaningful name to a set of related values.</p>
<p>For example, you can use an enum to define a set of possible status values for an order:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">enum</span> OrderStatus {
 Pending,
 Processing,
 Shipped,
 Delivered,
 Cancelled
}

<span class="hljs-keyword">let</span> orderStatus: OrderStatus = OrderStatus.Pending;
</code></pre>
<p>Enums can also have a custom set of numeric values or strings:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">enum</span> OrderStatus {
 Pending = <span class="hljs-number">1</span>,
 Processing = <span class="hljs-number">2</span>,
 Shipped = <span class="hljs-number">3</span>,
 Delivered = <span class="hljs-number">4</span>,
 Cancelled = <span class="hljs-number">5</span>
}

<span class="hljs-keyword">let</span> orderStatus: OrderStatus = OrderStatus.Pending;
</code></pre>
<p>Always name an enum with the first capital letter, and the name has to be in the singular form, as part of the naming convention.</p>
<p>Read <a target="_blank" href="https://medium.com/@alexefimenko/typescript-enums-5-real-world-use-cases-7ceccc423c18">this article</a> to explore the cases of TypeScript enums that are used in the real world.</p>
<h3 id="heading-using-namespaces">Using Namespaces</h3>
<p>Namespaces are a way to organize your code and prevent naming collisions. They allow you to create a container for your code, where you can define variables, classes, functions, and interfaces.</p>
<p>For example, you can use a namespace to group all the code related to a specific feature:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">namespace</span> OrderModule {
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Order { <span class="hljs-comment">/* … */</span> }
 <span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">cancelOrder</span>(<span class="hljs-params">order: Order</span>) </span>{ <span class="hljs-comment">/* … */</span> }
 <span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processOrder</span>(<span class="hljs-params">order: Order</span>) </span>{ <span class="hljs-comment">/* … */</span> }
}
<span class="hljs-keyword">let</span> order = <span class="hljs-keyword">new</span> OrderModule.Order();
OrderModule.cancelOrder(order);
</code></pre>
<p>You can also use namespaces to prevent naming collisions by providing a unique name for your code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">namespace</span> MyCompany.MyModule {
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> MyClass { <span class="hljs-comment">/* … */</span> }
}

<span class="hljs-keyword">let</span> myClass = <span class="hljs-keyword">new</span> MyCompany.MyModule.MyClass();
</code></pre>
<p>It’s important to note that namespaces are similar to modules, but they are used to organize the code and prevent naming collisions, while modules are used to load and execute the code.</p>
<h3 id="heading-using-typescript-infer-like-a-pro">Using Typescript <code>infer</code> Like a Pro</h3>
<p>Do you know how to get the type of the elements in the T0 array type and the return value type in the T1 function type? Give yourself a few seconds to think about it.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> T0 = <span class="hljs-built_in">string</span>[];
<span class="hljs-keyword">type</span> T1 = <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">string</span>;
</code></pre>
<p>We can use the type pattern matching technology provided by Typescript - <strong>conditional types</strong> and <strong>infer</strong> to complete the previous requirements.</p>
<p>Conditional types allow us to detect the relationship between 2 types and determine whether they are compatible. <strong>Infer is used to declare a type variable to store the type captured during pattern matching.</strong></p>
<p>Let’s see how to capture the type of the elements in the T0 array type:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> UnpackedArray&lt;T&gt; = T <span class="hljs-keyword">extends</span> (infer U)[] ? U : T
<span class="hljs-keyword">type</span> U0 = UnpackedArray&lt;T0&gt; <span class="hljs-comment">// string</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728548617512/d3f3f4fc-2067-4661-b2b9-8f21b5b91b19.webp" alt class="image--center mx-auto" /></p>
<p>In the above code, <code>T extends (infer U)[] ? U : T</code> is the syntax for conditional types, <code>infer U</code> in the extended clauses, introduce a new type variable U to store the inferred type.</p>
<p>For a better understanding, let’s demonstrate the execution flow of the <code>UnpackedArray</code> utility type.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728548941836/e5a846bc-a665-40db-bad2-2c502c0759ec.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728548948636/0365c586-e29e-47e3-9465-c187710a5008.webp" alt class="image--center mx-auto" /></p>
<p><strong>It should be noted that infer can only be used in the extends clause of the conditional type, and the type variable declared by infer is only available in the true branch of the conditional type.</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Wrong1&lt;T <span class="hljs-keyword">extends</span> (infer U)[]&gt; = T[<span class="hljs-number">0</span>] <span class="hljs-comment">// Error</span>
<span class="hljs-keyword">type</span> Wrong2&lt;T&gt; = (infer U)[] <span class="hljs-keyword">extends</span> T ? U : T <span class="hljs-comment">// Error</span>
<span class="hljs-keyword">type</span> Wrong3&lt;T&gt; = T <span class="hljs-keyword">extends</span> (infer U)[] ? T : U <span class="hljs-comment">// Error</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728549478690/56184506-2840-40ac-8cf0-a3b004053fac.webp" alt class="image--center mx-auto" /></p>
<p>For more use cases and more explanations, refer to <a target="_blank" href="https://levelup.gitconnected.com/using-typescript-infer-like-a-pro-f30ab8ab41c7">this article</a>.</p>
<h3 id="heading-using-typescript-conditional-types-like-a-pro">Using Typescript Conditional Types Like a Pro</h3>
<p>Have you used the <strong>Exclude, Extract, NonNullable, Parameters, and ReturnType</strong> utility types? Do you know how they work internally? In fact, the above Typescript built-in utility types are all developed based on <strong>Conditional Types</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728550508588/28c23180-48f0-4214-8c85-3eb83fbe11c3.gif" alt class="image--center mx-auto" /></p>
<p>Here, we first briefly understand the specific implementation of these TypeScript built-in utility types.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728550957675/7f43d5ed-021f-46dc-ab82-336a94dcab5a.webp" alt class="image--center mx-auto" /></p>
<p>These utility types are used for the following purposes:</p>
<ul>
<li><p>Exclude: Constructs a type by excluding it from <code>UnionType</code> all union members who are assigned to <code>ExcludedMembers</code>.</p>
</li>
<li><p>Extract: Constructs a type by extracting from <code>Type</code> all union members who are assigned to <code>Union</code>.</p>
</li>
<li><p>NonNullable: Constructs a type by excluding <code>null</code> and <code>undefined</code> from <code>Type</code>.</p>
</li>
<li><p>Parameters: Constructs a tuple type from the types used in the parameters of a function type <code>Type</code>.</p>
</li>
<li><p>ReturnType: Constructs a type consisting of the return type of the function <code>Type</code>.</p>
</li>
</ul>
<p>Here we look at a few usage examples:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728552644712/de138adc-d256-469f-ba52-7245b1c2fc83.webp" alt class="image--center mx-auto" /></p>
<p>If you want to master them thoroughly and create your own utility types.</p>
<p>The built-in utility types described earlier use the Conditional Types introduced in Typescript 2.8 internally. The syntax for this type is as follows:</p>
<pre><code class="lang-typescript">T <span class="hljs-keyword">extends</span> U ? X : Y
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728552989949/6bc31998-0972-43e1-b0b6-c80b9d367222.gif" alt class="image--center mx-auto" /></p>
<p>So what are the uses of conditional types? Let’s take an example here:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> IsString&lt;T&gt; = T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">string</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;
​
<span class="hljs-keyword">type</span> I0 = IsString&lt;<span class="hljs-built_in">number</span>&gt;;  <span class="hljs-comment">// false</span>
<span class="hljs-keyword">type</span> I1 = IsString&lt;<span class="hljs-string">"abc"</span>&gt;;  <span class="hljs-comment">// true</span>
<span class="hljs-keyword">type</span> I2 = IsString&lt;<span class="hljs-built_in">any</span>&gt;;  <span class="hljs-comment">// boolean</span>
<span class="hljs-keyword">type</span> I3 = IsString&lt;<span class="hljs-built_in">never</span>&gt;;  <span class="hljs-comment">// never</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728553113066/83c2f0e8-3911-40f2-8ccd-866b69771f2f.gif" alt class="image--center mx-auto" /></p>
<p>Refer <a target="_blank" href="https://javascript.plainenglish.io/use-typescript-conditional-types-like-a-pro-7baea0ad05c5">this article</a> to explore more.</p>
<h3 id="heading-what-are-k-t-and-v-in-typescript-generics">What are K, T, and V in Typescript Generics?</h3>
<p>Does it sound strange when you first see the <code>T</code> in Typescript generics?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728557080490/a40661aa-8381-474a-8040-fcbe34634e1a.gif" alt class="image--center mx-auto" /></p>
<p>The <code>T</code> in the figure is called a generic type parameter, and it is a type placeholder we wish to pass the identity function.</p>
<p>Just like passing parameters, we take the actual type specified by the user and chain it to the parameter type and return the value type.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728557294661/87fdff77-cfc9-4555-94de-388c3c2f833a.gif" alt class="image--center mx-auto" /></p>
<p>So what does T mean? The generic type parameter T in the figure represents Type; in fact, T can be replaced by any valid name. In addition to T, common generic variables are K, V, E, etc.</p>
<ul>
<li><p>K(Key): represents a type of key in an object.</p>
</li>
<li><p>V(Value): represents a type of value in an object.</p>
</li>
<li><p>E(Element): represents the element type.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728557631783/9ed8af4d-34ef-4e62-b56c-f52ddf9d50ff.gif" alt class="image--center mx-auto" /></p>
<p>Of course, you don’t have to define only one type parameter; you can introduce any number of type parameters. Here, we introduce a new parameter type U that extends the identity function we defined.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728558009796/07230413-07bf-43cd-a8e8-27efb48ff1cf.gif" alt class="image--center mx-auto" /></p>
<p>When calling the identity function, we can explicitly specify the actual type of the generic parameter. Of course, you can also not specify the type of the generic parameter, and let Typescript automatically complete the type reference for us.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728559728735/5f971d71-f6b6-4ae6-b021-4a4959ba3afa.gif" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://medium.com/web-tech-journals/think-you-know-generics-these-typescript-tricks-will-surprise-you-ea4ee22129a2">https://medium.com/web-tech-journals/think-you-know-generics-these-typescript-tricks-will-surprise-you-ea4ee22129a2</a></p>
<h3 id="heading-using-typescript-mapped-types-like-a-pro">Using Typescript Mapped Types Like a Pro</h3>
<p>Have you used the Partial, Required, Readonly, and Pick utility types?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728705609209/434122f2-7bb7-49d7-8205-9c93b44f4e36.webp" alt class="image--center mx-auto" /></p>
<p>Do you know how they work internally? If you want to master them thoroughly and create your own utility types, don’t miss the content below :)</p>
<p>User Registration is a widespread scenario in daily work. Here we can use Typescript to define a User in which all keys are required.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> User = {
  name: <span class="hljs-built_in">string</span>; 
  password: <span class="hljs-built_in">string</span>; 
  address: <span class="hljs-built_in">string</span>; 
  phone: <span class="hljs-built_in">string</span>;
};
</code></pre>
<p>Usually, for registered users, we allow users to modify only some user information. At this point, we can define a new UserPartial type representing the object type to update, in which all keys are optional.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> UserPartial = {
  name?: <span class="hljs-built_in">string</span>; 
  password?: <span class="hljs-built_in">string</span>; 
  address?: <span class="hljs-built_in">string</span>; 
  phone?: <span class="hljs-built_in">string</span>; 
};
</code></pre>
<p>For the scenario of viewing user information, we hope that all keys of the object type corresponding to the user object are read-only. For this requirement, we can define the Readonly User type.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ReadonlyUser = {
  <span class="hljs-keyword">readonly</span> name: <span class="hljs-built_in">string</span>;
  <span class="hljs-keyword">readonly</span> password: <span class="hljs-built_in">string</span>;
  <span class="hljs-keyword">readonly</span> address: <span class="hljs-built_in">string</span>;
  <span class="hljs-keyword">readonly</span> phone: <span class="hljs-built_in">string</span>;
};
</code></pre>
<p>Reviewing the 3 user-related types already defined, we will see that they contain a lot of duplicate code.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728706795938/6e05de75-293c-47a9-aabc-2d3a4971647d.gif" alt class="image--center mx-auto" /></p>
<p>So, how can we reduce the duplicate code in the above types? The answer is we can use the mapped type, which is a generic type that can be used to map the original object type to a new object type.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728707105453/1e31acf1-b34a-4476-b03f-82b8165cdc84.gif" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728707190286/6c330ec4-0d30-4b8a-a86c-d6db1e7ad142.gif" alt class="image--center mx-auto" /></p>
<p>The syntax for mapped types is as follows:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728707875037/7be47e97-87b8-4206-8a71-37813ff1d54a.webp" alt class="image--center mx-auto" /></p>
<p>Where P in K is similar to the JavaScript for … in the statement, which is used to iterate through all types in type K, and the T type variable, which is used to represent any type in Typescript.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728708285867/99a5755f-9020-4e15-995b-82e707583b3f.gif" alt class="image--center mx-auto" /></p>
<p>You can also use the additional modifiers read-only and question mark (?) in the mapping process. The corresponding modifiers are added and removed by adding the plus(+) and minus(-) prefixes. The default is to use the plus sign if no prefix is added.</p>
<p>We can now summarize the syntax of the common mapped type.</p>
<pre><code class="lang-typescript">{ [ P <span class="hljs-keyword">in</span> K ] : T }
{ [ P <span class="hljs-keyword">in</span> K ] ?: T }
{ [ P <span class="hljs-keyword">in</span> K ] -?: T }
{ <span class="hljs-keyword">readonly</span> [ P <span class="hljs-keyword">in</span> K ] : T }
{ <span class="hljs-keyword">readonly</span> [ P <span class="hljs-keyword">in</span> K ] ?: T }
{ -<span class="hljs-keyword">readonly</span> [ P <span class="hljs-keyword">in</span> K ] ?: T }
</code></pre>
<p>After introducing the syntax of common mapped types, let’s look at some examples:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728708706720/ab5b9e5c-b335-44c9-ae9a-dfce568c8365.webp" alt class="image--center mx-auto" /></p>
<p>Let’s look at how to redefine the PartialUser type using mapped types:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> MyPartial&lt;T&gt; = {
  [P <span class="hljs-keyword">in</span> keyof T]?: T[P];
};
<span class="hljs-keyword">type</span> UserPartial = MyPartial&lt;User&gt;;
</code></pre>
<p>In the above code, we define the MyPartial type-mapped type and then use it to map the User type to the UserPartial type. The <code>keyof</code> operator is used to get all the keys of a type, and its return type is a union type. The type variable P changes to a different type with each traversal, T[P], which is similar to the syntax for attribute access, and is used to get the type of the value corresponding to an attribute of the object type.</p>
<p>Let’s demonstrate the complete execution flow of MyPartial mapped types. If you are not sure, you can watch it several times to deepen your understanding of the TypeScript mapped type.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728709634291/abc46a30-7268-41b3-ba0e-d9b8e4296e40.gif" alt class="image--center mx-auto" /></p>
<p>Refer to <a target="_blank" href="https://javascript.plainenglish.io/using-typescript-mapped-types-like-a-pro-be10aef5511a">this article</a> to explore more.</p>
<h3 id="heading-using-typescript-template-literal-types-like-a-pro">Using Typescript Template Literal Types Like a Pro</h3>
<p>When developing web pages, we usually use a Tooltip or a Popover to display prompt messages or explanatory information. In order to meet some usage scenarios, Tooltop or Popover will allow the user to set their placement position. For example, top, bottom, left, right, etc.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728810093579/3e4bbffd-8887-4dbb-8ee4-bc5f23992198.webp" alt class="image--center mx-auto" /></p>
<p>Since string literal types can basically spell-check our string values, we define a <code>Side</code> type using Typescript’s type aliases.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Side = <span class="hljs-string">'top'</span> | <span class="hljs-string">'right'</span> | <span class="hljs-string">'bottom'</span> | <span class="hljs-string">'left'</span>;
<span class="hljs-keyword">let</span> side: Side = <span class="hljs-string">"rigth"</span>; <span class="hljs-comment">// Error</span>
<span class="hljs-comment">// Type '"rigth"' is not assignable to type 'Side'. </span>
<span class="hljs-comment">// Did you mean '"right"'?ts(2820)</span>
</code></pre>
<p>For the above 4 positions, it can already meet most scenarios. But if you want to set the placement position of the Tooltip more precisely, for example, let the Tooltip display in the upper area of the specified elements:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728810616301/8eb290a5-c2a5-440d-95bb-d79a0cac3453.webp" alt class="image--center mx-auto" /></p>
<p>Then the existing <code>Side</code> can’t meet the requirements, let’s define the new <code>Placement</code> type:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Placement = Side
  | <span class="hljs-string">"left-start"</span> | <span class="hljs-string">"left-end"</span> 
  | <span class="hljs-string">"right-start"</span> | <span class="hljs-string">"right-end"</span> 
  | <span class="hljs-string">"top-start"</span> | <span class="hljs-string">"top-end"</span> 
  | <span class="hljs-string">"bottom-start"</span> | <span class="hljs-string">"bottom-end"</span>
</code></pre>
<p>In the <code>Placement</code> type, in addition to the original 4 positions, we add 8 new positions, such as “left-start“, “left-end“, and “right-start“, which correspond to the 8 string literal types. Looking at these string literal types, we find some duplicate code “-start“ and “-end“. In addition, when defining these literal types, spelling errors may occur if you are not careful.</p>
<p>So, how can the above problems be solved better? This is where we can use the new template literal types introduced in TypeScript 4.1, which are used in the following way:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Alignment = <span class="hljs-string">'start'</span> | <span class="hljs-string">'end'</span>;
<span class="hljs-keyword">type</span> Side = <span class="hljs-string">'top'</span> | <span class="hljs-string">'right'</span> | <span class="hljs-string">'bottom'</span> | <span class="hljs-string">'left'</span>;
<span class="hljs-keyword">type</span> AlignedPlacement = <span class="hljs-string">`<span class="hljs-subst">${Side}</span>-<span class="hljs-subst">${Alignment}</span>`</span>;
<span class="hljs-keyword">type</span> Placement = Side | AlignedPlacement;
</code></pre>
<p>After reading the above code, do you think it is much simpler? Similar to template strings in Typescript, template literal types are enclosed in backticks and can contain placeholders of the form <code>${T}</code>. The actual type of the type variable T can be <strong>string, number, boolean, or bigint</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728811567160/6e1a6c1c-f163-4715-ab9c-e5fd326f3601.webp" alt class="image--center mx-auto" /></p>
<p>Template literal types provide us with the ability to concatenate string literals and convert literals of non-string primitive types to their corresponding string literal types. Here are some examples:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728812052582/edfa60e6-5c51-4e53-bb7d-6c62606b00c6.webp" alt class="image--center mx-auto" /></p>
<p>Refer to <a target="_blank" href="https://javascript.plainenglish.io/how-to-use-typescript-template-literal-types-like-a-pro-2e02a7db0bac">this article</a> to explore more.</p>
<h3 id="heading-the-purpose-of-declare-keyword-in-typescript">The Purpose of <code>declare</code> Keyword in Typescript</h3>
<p>When you open the *.d.ts file in TypeScript projects, you may see <code>delcare</code>. Do you know what <code>delcare</code> does?</p>
<p>In Typescript projects, you may import third-party JS-SDK in the form of script tags, such as importing the JS-SDK of the Google Maps platform.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>
   <span class="hljs-attr">src</span>=<span class="hljs-string">"https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&amp;callback=initMap&amp;v=weekly"</span> <span class="hljs-attr">defer</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>After initialization, you will call the API exposed by the JS-SDK in a Typescript file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728813917225/29df6796-d728-410e-a132-c9fe6dbdd035.webp" alt class="image--center mx-auto" /></p>
<p>Although you are using the API provided by JS-SDK according to the Google Maps development documentation, the Typescript compiler still prompts the corresponding error message for the above code. This is because the TypeScript compiler does not recognize the global variable <code>google</code>.</p>
<p>So how do we solve this problem? The answer is to use the declare keyword to declare the global <code>google</code> variable so that the Typescript compiler can recognize the global variable.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">var</span> google: <span class="hljs-built_in">any</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728814488703/5ce8198f-5ac3-40e1-a51e-8d5172017d40.webp" alt class="image--center mx-auto" /></p>
<p>Seeing this, do you get confused? Why can you use global variables like <code>JSON</code>, <code>Math</code>, or <code>Object</code> in Typescript projects, normally? This is because Typescript makes the declaration for us internally, and the global variables mentioned earlier are declared in the <strong>lib.es5.d.ts</strong> declaration file.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// typescript/lib/lib.es5.d.ts</span>
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">var</span> <span class="hljs-built_in">JSON</span>: <span class="hljs-built_in">JSON</span>;
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">var</span> <span class="hljs-built_in">Math</span>: <span class="hljs-built_in">Math</span>;
<span class="hljs-keyword">declare</span> <span class="hljs-keyword">var</span> <span class="hljs-built_in">Object</span>: ObjectConstructor;
</code></pre>
<p>In fact, in addition to declaring global variables, the declare keyword can also be used to declare global functions, global classes, and global enum types. Functions such as <code>eval</code>, <code>isNaN</code>, <code>encodeURI</code>, and <code>parseInt</code> that you may have used at work, also declare in the <strong>lib.es5.d.ts</strong> declaration file.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">eval</span>(<span class="hljs-params">x: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">any</span></span>;
<span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isNaN</span>(<span class="hljs-params"><span class="hljs-built_in">number</span>: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">boolean</span></span>;
<span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">encodeURI</span>(<span class="hljs-params">uri: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">string</span></span>;
<span class="hljs-keyword">declare</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">parseInt</span>(<span class="hljs-params"><span class="hljs-built_in">string</span>: <span class="hljs-built_in">string</span>, radix?: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">number</span></span>;
</code></pre>
<p>It should be noted that when declaring a global function, we do not include the specific implementation of the function. With the declaration file, TypeScript can recognize the global JavaScript functions.</p>
<p>Explore more <a target="_blank" href="https://javascript.plainenglish.io/purpose-of-declare-keyword-in-typescript-8431d9db2b10">here</a>.</p>
<h3 id="heading-how-to-define-object-type-with-unknown-structures-in-typescript">How To Define Object Type With Unknown Structures in Typescript</h3>
<p>Did you encounter similar errors when you were learning Typescript?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728816827200/46a9515a-4156-4c74-8dce-8124089add58.webp" alt class="image--center mx-auto" /></p>
<p>To fix this error, a very violent way is to use <code>any</code> type:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> user: <span class="hljs-built_in">any</span> = {}
user.id = <span class="hljs-string">"TS001"</span>;
user.name = <span class="hljs-string">"Bytefer"</span>;
</code></pre>
<p>Beside using <code>any</code> type, how many solutions do you know? In this article, I will introduce 3 other solutions. Before you continue reading, I suggest you take a moment to think about it.</p>
<p>One of the solutions is to use <code>type</code> or <code>interface</code> to define a <code>User</code> type:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> User {
  id: <span class="hljs-built_in">string</span>;
  name: <span class="hljs-built_in">string</span>;
}
<span class="hljs-keyword">let</span> user = {} <span class="hljs-keyword">as</span> User;
user.id = <span class="hljs-string">"TS001"</span>;
user.name = <span class="hljs-string">"Bytefer"</span>;
</code></pre>
<p>Although using the <code>User</code> type, the previous problem can be solved. But you set a new <code>age</code> property for the user object, the following error message will be displayed:</p>
<p><code>Property 'age' does not exist on type 'User'.ts(2339)</code></p>
<p>So, how should we solve the problem of dynamic property assignment? At this point, we can use TypeScript’s index signatures. When we only know the type of the object keys and values, we can use index signatures to define the type of that object. The syntax of the index signatures is as follows:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728817238160/08d4c326-7a88-4974-93d5-4205825e91f8.webp" alt class="image--center mx-auto" /></p>
<p><strong>The type of the key can only be string, number, symbol, or template literal type</strong>, while the type of the value can be any type.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728817282685/6dbac536-b6e6-46c0-90c4-c34f2a45c189.webp" alt class="image--center mx-auto" /></p>
<p>The <strong>template literal type</strong> is a new type introduced in TypeScript 4.1, and in combination with <strong>index signatures,</strong> we can define more powerful types.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728817360782/fd7295d2-0927-4922-9037-da331d350b41.webp" alt class="image--center mx-auto" /></p>
<p>In addition to using index signatures, we can also use TypeScript’s built-in utility type <code>Record</code> type to define the <code>User</code> type. The role of the <code>Record</code> utility type is as follows:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728817534969/aa9f7fec-7993-47b5-8e19-46e6d40e33b1.webp" alt class="image--center mx-auto" /></p>
<p>So what’s the difference between index signatures and a Record utility type? In some cases, they all define the expected type.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> user1: Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt; = { name: <span class="hljs-string">"Bytefer"</span> }; <span class="hljs-comment">// Ok</span>
<span class="hljs-keyword">const</span> user2: { [key: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">string</span> } = { name: <span class="hljs-string">"Bytefer"</span> }; <span class="hljs-comment">// Ok</span>
</code></pre>
<p>For index signatures, the key type can only be string, number, symbol, or template literal type. <strong>For the Record utility type, the key type can be a literal type or a union of literal types</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728817590126/15faf62a-b830-49ae-901e-f48178f7a486.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-using-typescript-type-predicates-for-precise-type-checking">Using Typescript Type Predicates for Precise Type Checking</h3>
<p>Type predicates are a powerful tool used to check and ensure at runtime that a variable belongs to a specific type. By using type predicates, we can achieve more precise type checking when writing type-safe code, thereby avoiding type errors and enhancing the robustness and maintainability of the code.</p>
<p>Suppose we have a union type representing animals, including cats(Cat) and dogs (Dog).</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Cat {
  kind: <span class="hljs-string">"cat"</span>;
  meow: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">interface</span> Dog {
  kind: <span class="hljs-string">"dog"</span>;
  bark: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">type</span> Animal = Cat | Dog;
</code></pre>
<p>Now, we want to write a function to check whether an <code>Animal</code> is of type <code>Cat</code>. At this point, we can use the type predicate:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isCat</span>(<span class="hljs-params">animal: Animal</span>): <span class="hljs-title">animal</span> <span class="hljs-title">is</span> <span class="hljs-title">Cat</span> </span>{
  <span class="hljs-keyword">return</span> animal.kind === <span class="hljs-string">"cat"</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">makeSound</span>(<span class="hljs-params">animal: Animal</span>) </span>{
  <span class="hljs-keyword">if</span> (isCat(animal)) {
    animal.meow(); <span class="hljs-comment">// Here, TypeScript knows that animal is of type Cat.</span>
  } <span class="hljs-keyword">else</span> {
    animal.bark(); <span class="hljs-comment">// Here, TypeScript knows that animal is of type Dog.</span>
  }
}
</code></pre>
<p>In the example above, we define a function name <code>isCat</code> and use the type predicate <code>animal is Cat</code> as the return type. The function checks if the <code>kind</code> property of the passed <code>animal</code> object is equal to “cat”. If it is, the function returns true and informs the Typescript compiler that, within this conditional branch, the <code>animal</code> variable is of type <code>Cat</code>.</p>
<p>By doing this, the <code>makeSound</code> function can accurately identify the specific type of <code>Animal</code> and call the methods specific to <code>Cat</code> or <code>Dog</code> in the corresponding conditional branches. This not only enhances the type safety of the code but also makes the code cleaner and easier to maintain.</p>
<h3 id="heading-using-typescript-recursive-like-a-pro">Using Typescript Recursive Like a Pro</h3>
<p>A linked list is a common data structure that contains a series of nodes, each node contains two parts: data and a pointer to the next node. The first node in the linked list is called the head node, and the last node is called the tail node.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729933712483/a705c21b-17be-4844-b0d5-f068d569f8f8.webp" alt class="image--center mx-auto" /></p>
<p>So, how do we define a linked table type in Typescript? If you want to use an <code>type</code> or <code>interface</code> to define a linked table type, we need to use the recursive type in Typescript. A recursive type is a type that can refer to itself. This type is useful when dealing with recursive structures because it allows us to define a type that can refer to itself to represent each node of a recursive structure.</p>
<p>Let’s take a look at how to use recursive types to define the type of a singly linked list:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> ListNode&lt;T&gt; {
  data: T;
  next: ListNode&lt;T&gt; | <span class="hljs-literal">null</span>;
}

<span class="hljs-keyword">interface</span> LinkedList&lt;T&gt; {
  head: ListNode&lt;T&gt; | <span class="hljs-literal">null</span>;
  tail: ListNode&lt;T&gt; | <span class="hljs-literal">null</span>;
  length: <span class="hljs-built_in">number</span>;
  get(index: <span class="hljs-built_in">number</span>): ListNode&lt;T&gt; | <span class="hljs-literal">null</span>;
  insert(index: <span class="hljs-built_in">number</span>, value: T): <span class="hljs-built_in">boolean</span>;
  remove(index: <span class="hljs-built_in">number</span>): ListNode&lt;T&gt; | <span class="hljs-literal">null</span>;
}
</code></pre>
<p>In the above code, <code>ListNode&lt;T&gt;</code> represents the type of the chain node, and contains two properties, <code>data</code> and <code>next</code>, where the <code>data</code> property is used to store the value of the node, and the <code>next</code> property is used to store the pointer to the next node. Note that when the next property is not empty, it is of type <code>ListNode&lt;T&gt;</code>, which uses Typescript’s recursive types. And <code>LinkedList&lt;T&gt;</code> represents the type of a singly linked list, which contains the head node and the tail node, as well as the length property and some methods to manipulate the list.</p>
<p>For more details, refer to <a target="_blank" href="https://javascript.plainenglish.io/using-typescript-recursive-types-like-a-pro-caae262cf2">this article</a>.</p>
<h3 id="heading-use-returntype-and-awaited">Use ReturnType and Awaited</h3>
<ul>
<li><p>To get the return type of the function, use <strong>ReturnType</strong>.</p>
</li>
<li><p>To get the return type of an async function, wrap it in <strong>Awaited.</strong></p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loader</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> {…}
}
<span class="hljs-keyword">type</span> LoaderData = Awaited&lt;ReturnType&lt;<span class="hljs-keyword">typeof</span> loader&gt;&gt;
</code></pre>
<h2 id="heading-object-oriented-programming-in-typescript">Object-Oriented Programming in TypeScript</h2>
<p>Object-Oriented Programming (OOP) is one of the most widely used programming paradigms in software development. But it’s also one of the most understood.</p>
<p>This section will help you gain a solid grasp of OOP in Typescript by walking you through the language features that support it, and then showing how these features naturally give rise to the four foundation principles: inheritance, polymorphism, encapsulation, and abstraction.</p>
<h3 id="heading-typescript-language-features">TypeScript Language Features</h3>
<p>In this section, we will explore TypeScript’s features that facilitate OOP implementation. Similar mechanisms exist in other object-oriented languages, such as Java or C#, though they may vary in syntax while preserving the core concepts.</p>
<ol>
<li><strong>Objects</strong></li>
</ol>
<p>An object is a data type that stores a collection of values organized into key/value pairs. These may include primitive data or other objects.</p>
<p>In the following example, the <code>person</code> object stores various pieces of information, such as the key <code>name</code>, which contains the value <code>"Lucas"</code> of type <code>string</code>, and the <code>address</code> key, which holds another object.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> person = {
  name: <span class="hljs-string">"Lucas"</span>, <span class="hljs-comment">// primitive value of type string</span>
  surname: <span class="hljs-string">"Garcez"</span>,
  age: <span class="hljs-number">28</span>, <span class="hljs-comment">// primitive value of type number</span>
  address: {
    <span class="hljs-comment">// object type containing the keys "city" and "country"</span>
    city: <span class="hljs-string">"Melbourne"</span>,
    country: <span class="hljs-string">"Australia"</span>,
  },
};
</code></pre>
<ol start="2">
<li><strong>Classes, Attributes, and Methods</strong></li>
</ol>
<p>A class serves as a blueprint for creating objects. It specifies an object’s structure and behavior through its attributes and methods. Attributes outline the data structure (keys and value types), whereas methods define the actions that can be performed on those attributes.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Person {
  name: <span class="hljs-built_in">string</span>; <span class="hljs-comment">// attribute</span>
  surname: <span class="hljs-built_in">string</span>; <span class="hljs-comment">// attribute</span>
  age: <span class="hljs-built_in">number</span>; <span class="hljs-comment">// attribute</span>

  <span class="hljs-comment">// constructor method (special method)</span>
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">name: <span class="hljs-built_in">string</span>, surname: <span class="hljs-built_in">string</span>, age: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.name = name;
    <span class="hljs-built_in">this</span>.surname = surname;
    <span class="hljs-built_in">this</span>.age = age;
  }

  <span class="hljs-comment">// method to obtain the full name: "Lucas Garcez"</span>
  getFullName() {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> <span class="hljs-subst">${<span class="hljs-built_in">this</span>.surname}</span>`</span>;
  }
}
</code></pre>
<ol start="3">
<li><strong>Constructor Method</strong></li>
</ol>
<p>This constructor is a special method within a class. It’s automatically invoked when a new object is created. Constructors are responsible for initializing the class attributes with values provided during object creation.</p>
<p>In TypeScript, the constructor is defined using the constructor keyword, as you can see in the example above.</p>
<ol start="4">
<li><strong>Instance</strong></li>
</ol>
<p>An instance refers to an object created from a class. For example, using the class <code>Person</code> mentioned above, you can create an object named <code>lucas</code>. Therefore, <code>lucas</code> is an instance of the class <code>Person</code>. To create an instance of an object in JavaScript or TypeScript, you use the keyword <code>new</code>, as demonstrated below:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> lucas = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Lucas"</span>, <span class="hljs-string">"Garcez"</span>, <span class="hljs-number">28</span>);
lucas.name; <span class="hljs-comment">// "Lucas"</span>
lucas.getFullName(); <span class="hljs-comment">// "Lucas Garcez"</span>
</code></pre>
<p>It’s important to note that you can create multiple objects (instances) from the same class. Although these objects share the same structure (attributes and methods), they are independent and occupy separate memory spaces within the program.</p>
<p>For instance, when creating a new object:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> maria = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Maria"</span>, <span class="hljs-string">"Oliveira"</span>, <span class="hljs-number">19</span>);
</code></pre>
<p>You now have a new instance of the <code>Person</code> class that doesn't interfere with the previously created <code>lucas</code> object. Each instance maintains its own values and behaviors, ensuring that manipulating one object doesn’t affect to the others.</p>
<ol start="5">
<li><strong>Interfaces</strong></li>
</ol>
<p>An interface defines a contract establishing which attributes and methods a class must implement. In TypeScript, this relationship is established using the keyword implements. When a class implements an interface, it must include all the attributes and methods specified by that interface and their respective types.</p>
<p>In the following example, you have a banking system where a customer can have either <code>CurrentAccount</code> or <code>SavingsAccount</code> account. Both options must adhere to the bank’s general account rules defined by the <code>BankAccount</code> interface.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Contract defining the attributes and methods of a bank account</span>
<span class="hljs-keyword">interface</span> BankAccount {
  balance: <span class="hljs-built_in">number</span>;
  deposit(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span>;
  withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">class</span> CurrentAccount <span class="hljs-keyword">implements</span> BankAccount {
  balance: <span class="hljs-built_in">number</span>;
  <span class="hljs-comment">// The class can have other attributes and methods</span>
  <span class="hljs-comment">// beyond those specified in the interface</span>
  overdraftLimit: <span class="hljs-built_in">number</span>;

  deposit(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.balance += amount;
  }

  withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (amount &lt;= <span class="hljs-built_in">this</span>.balance) {
      <span class="hljs-built_in">this</span>.balance -= amount;
    }
  }
}

<span class="hljs-keyword">class</span> SavingsAccount <span class="hljs-keyword">implements</span> BankAccount {
  balance: <span class="hljs-built_in">number</span>;

  deposit(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-comment">// can have different logic from CurrentAccount</span>
    <span class="hljs-comment">// but must respect the method signature,</span>
    <span class="hljs-comment">// i.e., parameters (amount: number) and return type (void)</span>
  }

  withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-comment">// ...</span>
  }
}
</code></pre>
<ol start="5">
<li><strong>Abstract Classes</strong></li>
</ol>
<p>Just like interfaces, abstract classes define a model or contract that other classes must follow. But while interfaces only describe the structure of the class without providing implementations, an abstract class can include method declarations and concrete implementations.</p>
<p>Unlike regular classes, though, abstract classes can not be instantiated directly — they exist solely as a base from which other classes can inherit their methods or attributes.</p>
<p>In Typescript, the abstract keyword is used to define an abstract class. In the following example, you will refactor the banking system by replacing an interface with an abstract class to define behaviors for all bank accounts.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Abstract class that serves as the base for any type of bank account</span>
<span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> BankAccount {
  balance: <span class="hljs-built_in">number</span>;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">initialBalance: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.balance = initialBalance;
  }

  <span class="hljs-comment">// Concrete method (with implementation)</span>
  deposit(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.balance += amount;
  }

  <span class="hljs-comment">// Abstract method (must be implemented by subclasses)</span>
  <span class="hljs-keyword">abstract</span> withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">class</span> CurrentAccount <span class="hljs-keyword">extends</span> BankAccount {
  withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">const</span> fee = <span class="hljs-number">2</span>; <span class="hljs-comment">// Current accounts have a fixed withdrawal fee</span>
    <span class="hljs-keyword">const</span> totalAmount = amount + fee;

    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.balance &gt;= totalAmount) {
      <span class="hljs-built_in">this</span>.balance -= totalAmount;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Insufficient balance."</span>);
    }
  }
}

<span class="hljs-keyword">class</span> SavingsAccount <span class="hljs-keyword">extends</span> BankAccount {
  withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.balance &gt;= amount) {
      <span class="hljs-built_in">this</span>.balance -= amount;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Insufficient balance."</span>);
    }
  }
}

<span class="hljs-comment">// ❌ Error! Cannot instantiate an abstract class</span>
<span class="hljs-keyword">const</span> genericAccount = <span class="hljs-keyword">new</span> BankAccount(<span class="hljs-number">1000</span>); <span class="hljs-comment">// Error</span>

<span class="hljs-comment">// ✅ Creating a current account</span>
<span class="hljs-keyword">const</span> currentAccount = <span class="hljs-keyword">new</span> CurrentAccount(<span class="hljs-number">2000</span>); <span class="hljs-comment">// uses the BankAccount constructor</span>
currentAccount.deposit(<span class="hljs-number">500</span>); <span class="hljs-comment">// uses the deposit method from BankAccount</span>
currentAccount.withdraw(<span class="hljs-number">300</span>); <span class="hljs-comment">// uses the withdraw method from CurrentAccount</span>

<span class="hljs-comment">// ✅ Creating a savings account</span>
<span class="hljs-keyword">const</span> savingsAccount = <span class="hljs-keyword">new</span> SavingsAccount(<span class="hljs-number">1500</span>); <span class="hljs-comment">// uses the BankAccount constructor</span>
savingsAccount.deposit(<span class="hljs-number">1100</span>); <span class="hljs-comment">// uses the deposit method from BankAccount</span>
savingsAccount.withdraw(<span class="hljs-number">500</span>); <span class="hljs-comment">// uses the withdraw method from SavingsAccount</span>
</code></pre>
<h3 id="heading-object-oriented-programming-principles">Object-Oriented Programming Principles</h3>
<p>Now that you understand the key language mechanisms, you can formalize the pillars of Object-Oriented Programming that guide the creation of systems that are better organized, reusable, and scalable.</p>
<ol>
<li><strong>Inheritance — Superclass and Subclass</strong></li>
</ol>
<p>Inheritance is a mechanism that allows a class to derive characteristics from another class. When a class B inherits from a class A, it means that class B automatically acquires the attributes and methods of A without needing to redefine them.</p>
<p>You can visualize this relationship as a parent-child structure, when A is the superclass (parent/base class) and B is the subclass (derived/child class). A subclass can use inherited resources, add new behaviors, or override superclass methods to address specific needs.</p>
<p>We’ve already discussed inheritance when learning about abstract classes, but inheritance can also be applied to concrete classes. This allows for code reuse and behavior specialization.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// BankAccount is now a regular class where you define attributes and methods</span>
<span class="hljs-comment">// that will be reused by the child class CurrentAccount</span>
<span class="hljs-keyword">class</span> BankAccount {
  balance: <span class="hljs-built_in">number</span> = <span class="hljs-number">0</span>;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">initialBalance: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.balance = initialBalance;
  }

  deposit(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.balance += amount;
  }

  withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (amount &lt;= <span class="hljs-built_in">this</span>.balance) {
      <span class="hljs-built_in">this</span>.balance -= amount;
    }
  }
}

<span class="hljs-comment">// CurrentAccount is a subclass of BankAccount, meaning </span>
<span class="hljs-comment">// it inherits its attributes and methods.</span>
<span class="hljs-keyword">class</span> CurrentAccount <span class="hljs-keyword">extends</span> BankAccount {
  overdraftLimit: <span class="hljs-built_in">number</span>; <span class="hljs-comment">// new attribute exclusive to CurrentAccount</span>

  <span class="hljs-comment">// When specifying a constructor method for a subclass,</span>
  <span class="hljs-comment">// we need to call another special method, "super".</span>
  <span class="hljs-comment">// This method calls the superclass (BankAccount) constructor to ensure</span>
  <span class="hljs-comment">// it is initialized before creating the CurrentAccount object itself.</span>
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">initialBalance: <span class="hljs-built_in">number</span>, overdraftLimit: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">super</span>(initialBalance); <span class="hljs-comment">// Must match the superclass constructor method signature</span>
    <span class="hljs-built_in">this</span>.overdraftLimit = overdraftLimit;
  }

  <span class="hljs-comment">// Even though the withdraw method already exists in the superclass (BankAccount),</span>
  <span class="hljs-comment">// it is overridden here. This means every time a CurrentAccount</span>
  <span class="hljs-comment">// object calls the withdraw method, this implementation will be used, </span>
  <span class="hljs-comment">// ignoring the superclass method.</span>
  override withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">const</span> totalAvailable = <span class="hljs-built_in">this</span>.balance + <span class="hljs-built_in">this</span>.overdraftLimit;
    <span class="hljs-keyword">if</span> (amount &gt; <span class="hljs-number">0</span> &amp;&amp; amount &lt;= totalAvailable) {
      <span class="hljs-built_in">this</span>.balance -= amount;
    }
  }
}

<span class="hljs-comment">// Creating a CurrentAccount with an initial balance of $0.00</span>
<span class="hljs-comment">// and an overdraft limit of $100.</span>
<span class="hljs-keyword">const</span> currentAccount = <span class="hljs-keyword">new</span> CurrentAccount(<span class="hljs-number">0</span>, <span class="hljs-number">100</span>);

<span class="hljs-comment">// Making a $200 deposit by calling the deposit method</span>
<span class="hljs-comment">// In this case, the method from BankAccount will be invoked</span>
<span class="hljs-comment">// since deposit was not overridden in CurrentAccount</span>
currentAccount.deposit(<span class="hljs-number">200</span>); <span class="hljs-comment">// balance: 200</span>

<span class="hljs-comment">// Withdrawing $250 by calling the withdraw method</span>
<span class="hljs-comment">// In this case, the method from CurrentAccount will be invoked</span>
<span class="hljs-comment">// as it has been overridden in its definition</span>
currentAccount.withdraw(<span class="hljs-number">250</span>); <span class="hljs-comment">// balance: -50</span>
</code></pre>
<ol start="2">
<li><strong>Polymorphism</strong></li>
</ol>
<p>Polymorphism is a concept that often creates confusion in Object-Oriented Programming. But in practice, it’s merely a natural consequence of using interfaces and inheritance.</p>
<p>The term polymorphism originates from Greek and means “many forms“ (poly = many, morphos = forms). This concept allows objects from different classes to respond to the same method call but with distinct implementations, making code more flexible and reusable.</p>
<p>To clarify this concept, let’s consider a practical example. Suppose you have a function named <code>sendMoney</code>, responsible for processing a financial transaction, transferring a certain amount from account A to account B. The only requirement is that both accounts follow a common contract, ensuring the methods <code>withdraw</code> and <code>deposit</code> are available.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// BankAccount could be an interface, a concrete class,</span>
<span class="hljs-comment">// or an abstract class. For the sendMoney function, the specific implementation</span>
<span class="hljs-comment">// does not matter—only that BankAccount includes withdraw and deposit methods.</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendMoney</span>(<span class="hljs-params">
  sender: BankAccount,
  receiver: BankAccount,
  amount: <span class="hljs-built_in">number</span>
</span>) </span>{
  sender.withdraw(amount);
  receiver.deposit(amount);
}

<span class="hljs-keyword">const</span> lucasAccount = <span class="hljs-keyword">new</span> CurrentAccount(<span class="hljs-number">500</span>, <span class="hljs-number">200</span>);
<span class="hljs-keyword">const</span> mariaAccount = <span class="hljs-keyword">new</span> SavingsAccount(<span class="hljs-number">300</span>);

<span class="hljs-comment">// transferring $100 from Lucas to Maria</span>
sendMoney(lucasAccount, mariaAccount, <span class="hljs-number">100</span>);
</code></pre>
<h4 id="heading-polymorphic-methods"><strong>Polymorphic Methods:</strong></h4>
<p>The <code>withdraw</code> and <code>deposit</code> methods are called within the <code>sendMoney</code> function without requiring the function to know whether it is dealing with a <code>CurrentAccount</code> or <code>SavingsAccount</code>. Each class implements <code>withdraw</code> according to its own rules, demonstrating the concept of polymorphism.</p>
<h4 id="heading-decoupling"><strong>Decoupling:</strong></h4>
<p>The <code>sendMoney</code> function does not depend on the specific type of bank account. Any class that extends <code>BankAccount</code> (if it's a class) or implements <code>BankAccount</code> (if it's an interface) can be used without requiring modifications to the <code>sendMoney</code> function.</p>
<p>With this approach, you ensure flexibility and code reusability, as new account types can be introduced without affecting the functionality of <code>sendMoney</code>.</p>
<ol start="3">
<li><strong>Encapsulation</strong></li>
</ol>
<p>Encapsulation is one of the fundamental principles of OOP, and its concept can be applied to any programming paradigm. It involves hiding the internal implementation details of a module, a class, or a function, or any other software components, exposing only what is necessary for external use. This improves code security, maintainability, and modularity by preventing unauthorized access and ensuring controlled interactions.</p>
<h4 id="heading-access-modifiers-public-private-and-protected"><strong>Access Modifiers –</strong> <code>public</code>, <code>private</code>, and <code>protected</code></h4>
<p>In OOP, encapsulation is essential for controlling the visibility and access to methods and attributes within a class. In TypeScript, this is achieved using access modifiers, which are defined by the keywords <code>public</code>, <code>protected</code>, and <code>private</code>.</p>
<ul>
<li><p><code>public</code> – Allows the attribute or method to be accessed from anywhere, both inside and outside the class. This is the default visibility, meaning that if no access modifier is specified in the code, TypeScript assumes it as <code>public</code>.</p>
</li>
<li><p><code>protected</code> – Allows access within the class and its subclasses but prevents external access.</p>
</li>
<li><p><code>private</code> – Restricts access to the attribute or method only within the class itself.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Person {
  <span class="hljs-keyword">private</span> firstName: <span class="hljs-built_in">string</span>; <span class="hljs-comment">// Accessible only within the class itself</span>
  <span class="hljs-keyword">private</span> lastName: <span class="hljs-built_in">string</span>; <span class="hljs-comment">// Accessible only within the class itself</span>
  <span class="hljs-keyword">protected</span> birthDate: <span class="hljs-built_in">Date</span>; <span class="hljs-comment">// Accessible by subclasses but not from outside</span>

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">firstName: <span class="hljs-built_in">string</span>, lastName: <span class="hljs-built_in">string</span>, birthDate: <span class="hljs-built_in">Date</span></span>) {
    <span class="hljs-built_in">this</span>.firstName = firstName;
    <span class="hljs-built_in">this</span>.lastName = lastName;
    <span class="hljs-built_in">this</span>.birthDate = birthDate;
  }

  <span class="hljs-comment">// Public method that can be accessed from anywhere</span>
  <span class="hljs-keyword">public</span> getFullName(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.firstName}</span> <span class="hljs-subst">${<span class="hljs-built_in">this</span>.lastName}</span>`</span>;
  }
}

<span class="hljs-comment">// The Professor class inherits from Person and can access</span>
<span class="hljs-comment">// attributes and methods according to their access modifiers.</span>
<span class="hljs-keyword">class</span> Professor <span class="hljs-keyword">extends</span> Person {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">firstName: <span class="hljs-built_in">string</span>, lastName: <span class="hljs-built_in">string</span>, birthDate: <span class="hljs-built_in">Date</span></span>) {
    <span class="hljs-built_in">super</span>(firstName, lastName, birthDate); <span class="hljs-comment">// Calls the superclass (Person) constructor</span>
  }

  getProfile() {
    <span class="hljs-built_in">this</span>.birthDate; <span class="hljs-comment">// ✅ Accessible because it is protected</span>
    <span class="hljs-built_in">this</span>.getFullName(); <span class="hljs-comment">// ✅ Accessible because it is public</span>
    <span class="hljs-built_in">this</span>.firstName; <span class="hljs-comment">// ❌ Error! Cannot be accessed because it is private in the Person class</span>
    <span class="hljs-built_in">this</span>.lastName; <span class="hljs-comment">// ❌ Error! Cannot be accessed because it is private in the Person class</span>
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Creating an instance of Professor</span>
  <span class="hljs-keyword">const</span> lucas = <span class="hljs-keyword">new</span> Professor(<span class="hljs-string">"Lucas"</span>, <span class="hljs-string">"Garcez"</span>, <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-string">"1996-02-06"</span>));

  <span class="hljs-comment">// Testing direct access to attributes and methods</span>
  lucas.birthDate; <span class="hljs-comment">// ❌ Error! birthDate is protected and can only be accessed within the class or subclasses</span>
  lucas.getFullName(); <span class="hljs-comment">// ✅ Accessible because it is a public method</span>
  lucas.firstName; <span class="hljs-comment">// ❌ Error! firstName is private and cannot be accessed outside the Person class</span>
  lucas.lastName; <span class="hljs-comment">// ❌ Error! lastName is also private and inaccessible outside the Person class</span>
}
</code></pre>
<h4 id="heading-access-modifiers-table"><strong>Access Modifiers Table</strong></h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Modifier</strong></td><td><strong>Access within the class</strong></td><td><strong>Access in subclass</strong></td><td><strong>Access outside the class</strong></td></tr>
</thead>
<tbody>
<tr>
<td><code>public</code></td><td>✅ Yes</td><td>✅ Yes</td><td>✅ Yes</td></tr>
<tr>
<td><code>protected</code></td><td>✅ Yes</td><td>✅ Yes</td><td>❌ No</td></tr>
<tr>
<td><code>private</code></td><td>✅ Yes</td><td>❌ No</td><td>❌ No</td></tr>
</tbody>
</table>
</div><ol start="4">
<li><strong>Abstraction</strong></li>
</ol>
<p>This concept of abstraction frequently confuses because its meaning goes beyond the technical context. If you look up the definition of the word in English, the Cambridge Dictionary defines <strong>"abstract"</strong> as:</p>
<blockquote>
<p><em>Something that exists as an idea, feeling, or quality, rather than as a material object.</em></p>
</blockquote>
<p>This definition can be directly applied to OOP: Abstraction represents an ideal or concept without going into concrete implementation details.</p>
<p>Many online references describe abstraction as “hiding implementation details“, which can be misleading since this concept is more closely related to encapsulation. In OOP, abstraction does not mean hiding details but defining constructs through abstract classes and interfaces.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Abstraction using interface</span>
<span class="hljs-keyword">interface</span> BankAccountInterface {
  balance: <span class="hljs-built_in">number</span>;
  deposit(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span>;
  withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span>;
}

<span class="hljs-comment">// Abstraction using class</span>
<span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> BankAccountClass {
  balance: <span class="hljs-built_in">number</span>;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">initialBalance: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.balance = initialBalance;
  }

  <span class="hljs-comment">// Concrete method (with implementation)</span>
  deposit(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.balance += amount;
  }

  <span class="hljs-comment">// Abstract method (must be implemented by subclasses)</span>
  <span class="hljs-keyword">abstract</span> withdraw(amount: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span>;
}
</code></pre>
<p>In the examples above, both <code>BankAccountInterface</code> and <code>BankAccountClass</code> are examples of abstraction as they define contracts that must be implemented by those who use them.</p>
<h2 id="heading-typescript-visualized-15-most-used-utility-types">Typescript Visualized: 15 Most Used Utility Types</h2>
<p>In the process of using Typescript, we are programming type-oriented manner. In order to meet several work scenarios, we need to transform the known type. For the convenience of TypeScript users, the TypeScript team has provided us with many built-in utility types. With these utility types, we can easily convert types, extract types, exclude types, or get the parameter type or return type value of the function.</p>
<p>I picked 15 very useful utility built-in types and introduced their usage and internal working principles in the form of images or animations. After that, I believe you can really master the usage of these utility built-in types.</p>
<p><a target="_blank" href="https://4markdown.com/5-game-changing-typescript-utility-types-you-should-master/">https://4markdown.com/5-game-changing-typescript-utility-types-you-should-master/</a></p>
<h3 id="heading-partiallttypegt">Partial&lt;Type&gt;</h3>
<p>Constructs a type with all the properties of <code>Type</code> set to optional.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729224407847/e9d5f71b-64b8-4691-ac60-74e7c02a81b6.webp" alt class="image--center mx-auto" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">/**
 * Make all properties in T optional. 
 * typescript/lib/lib.es5.d.ts
 */</span>
<span class="hljs-keyword">type</span> Partial&lt;T&gt; = {
    [P <span class="hljs-keyword">in</span> keyof T]?: T[P];
};
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729224441324/80d6d4dd-c914-4e29-a334-8758576be5e3.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-requiredlttypegt">Required&lt;Type&gt;</h3>
<p>Constructs a type consisting of all properties of <code>Type</code> set to the required. The opposite of <code>Partial</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729224629702/7a9c8d2f-570f-4275-8445-9207d90d876d.webp" alt class="image--center mx-auto" /></p>
<pre><code class="lang-typescript"><span class="hljs-comment">/**
 * Make all properties in T required.
 * typescript/lib/lib.es5.d.ts
 */</span>
<span class="hljs-keyword">type</span> Required&lt;T&gt; = {
    [P <span class="hljs-keyword">in</span> keyof T]-?: T[P];
};
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729224653257/7550a935-c20d-42bb-88e7-7f732c3eca09.gif" alt class="image--center mx-auto" /></p>
<p>For more utility types, explore <a target="_blank" href="https://javascript.plainenglish.io/15-utility-types-that-every-typescript-developer-should-know-6cf121d4047c">here</a>.</p>
<h2 id="heading-typescript-index-signature-explained">Typescript Index Signature Explained</h2>
<p>An index signature is defined using square brackets <code>[]</code> and the type of keys, followed by a colon and the type for the corresponding values. It enables Typescript to understand and enforce the expected structure of the object.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> MyStats {
  [key: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">number</span>;
}
<span class="hljs-keyword">const</span> scores: MyStats = {
  total: <span class="hljs-number">50</span>,
  average:<span class="hljs-number">80</span>
}
<span class="hljs-comment">// index siganture enforce the type constraint</span>
<span class="hljs-comment">// here, the value must be a number</span>
<span class="hljs-keyword">const</span> scores2: MyStats = {
  total: <span class="hljs-string">"50"</span>, <span class="hljs-comment">//Type 'string' is not assignable to type 'number'.(2322)</span>
  average:<span class="hljs-number">80</span>
}
</code></pre>
<p>Note that index signatures can use different key types, such as string, number, symbol, or literal type, and the associated value type can be any valid TypeScript type.</p>
<h3 id="heading-mixing-an-index-signature-with-explicit-members">Mixing an index signature with explicit members</h3>
<p>In Typescript, we can mix an index signature with explicit member declarations. It’s helpful for cases requiring a combination of known and dynamic properties.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> CarConfiguration {
  [feature: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">number</span>;
  price: <span class="hljs-built_in">number</span>;
}
</code></pre>
<p>When we mix index signatures with explicit members, all explicit members need to conform to the index signature types.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// invalid case</span>
<span class="hljs-keyword">interface</span> CarConfiguration {
  [feature: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">number</span>;
  price: <span class="hljs-built_in">number</span>;
  model: <span class="hljs-built_in">string</span>; <span class="hljs-comment">// Error: Property 'model' of type 'string' is not assignable to 'string' index type 'number'</span>
}

<span class="hljs-comment">// valid</span>
<span class="hljs-keyword">interface</span> CarConfiguration {
  [feature: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">number</span> | <span class="hljs-built_in">string</span>;
  price: <span class="hljs-built_in">number</span>;
  model: <span class="hljs-built_in">string</span>;
}
</code></pre>
<h3 id="heading-read-only-index-signature">Read-only index signature</h3>
<p>Index signature supports <code>readonly</code> modifier. By applying <code>readonly</code> modifier, the properties in the object will be immutable.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Car {
  <span class="hljs-keyword">readonly</span> [key: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-keyword">const</span> toyota: Car = {hybrid: <span class="hljs-literal">true</span>, luxury: <span class="hljs-literal">false</span>};
toyota.hybrid = <span class="hljs-literal">false</span>; <span class="hljs-comment">//Error: Index signature in type 'Car' only permits reading.(2542)</span>
</code></pre>
<p>In the above example, an error occurs when trying to modify <code>hybrid</code> property because the interface only allows for reading, not writing.</p>
<h3 id="heading-how-to-use-an-index-signature">How to use an index signature</h3>
<p>Let’s consider a real-world example of how index signatures can be used. Imagine you are developing an application with various features. Each feature includes its own set of settings, which can also be enabled or disabled.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> FeatureConfig {
  [feature: <span class="hljs-built_in">string</span>]: {
    enabled: <span class="hljs-built_in">boolean</span>;
    settings: Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">boolean</span>&gt;;
  }
}
</code></pre>
<p>In this example, we define an interface named <code>FeatureConfig</code>. It uses an index signature to allow dynamic property names of type <code>string</code> associated with an<code>enabled</code> boolean property and a <code>settings</code> object. It is handy for representing configurations with dynamic feature names and associated settings. For example, we can apply the interface to the following object.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> features: FeatureConfig = {
  profile: {
    enabled: <span class="hljs-literal">true</span>,
    settings: {
      showPhoto: <span class="hljs-literal">true</span>,
      allowEdit: <span class="hljs-literal">false</span>,
    },
  },
  notification: {
    enabled: <span class="hljs-literal">false</span>,
    settings: {
      richText: <span class="hljs-literal">true</span>,
      batchMode: <span class="hljs-literal">true</span>
    },
  }
};
</code></pre>
<p>In the <code>features</code> object, the feature names can vary, but the structure for each feature remains consistent. Each feature is expected to have an <code>enabled</code> boolean and a <code>settings</code> object.</p>
<p>To improve the type safety, can we apply a union-type constraint to the <code>feature</code> name in the above interface?</p>
<p>If the set of features in our application is known, we can define the union of string literals named<code>FeatureType</code>.</p>
<p>The key of the index signature does not support the union type, but we can work around it using a mapped type.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> FeatureType = <span class="hljs-string">'profile'</span> | <span class="hljs-string">'notification'</span> | <span class="hljs-string">'reporting'</span>;

<span class="hljs-keyword">type</span> FeatureConfig2 = {
  [feature <span class="hljs-keyword">in</span> FeatureType]: {
    enabled: <span class="hljs-built_in">boolean</span>;
    settings: Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">boolean</span>&gt;;
  }
}
</code></pre>
<p><code>[feature in FeatureType]</code>is a mapped type that iterates over each string literal in the union type <code>FeatureType</code> (which includes <code>'profile'</code>, <code>'notification'</code>, and <code>'reporting'</code>), and it uses each value as the resulting type's property name.</p>
<p>Here’s an example of how we might use it:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> allFeatures: FeatureConfig2 = {
  profile: {
    enabled: <span class="hljs-literal">true</span>,
    settings: {
      showPhoto: <span class="hljs-literal">true</span>,
      allowEdit: <span class="hljs-literal">false</span>,
    },
  },
  notification: {
    enabled: <span class="hljs-literal">false</span>,
    settings: {
      richText: <span class="hljs-literal">true</span>,
      batchMode: <span class="hljs-literal">true</span>
    },
  },
    reporting: {
    enabled: <span class="hljs-literal">true</span>,
    settings: {
      template: <span class="hljs-literal">false</span>,
      advanceExport: <span class="hljs-literal">true</span>
    },
  },
};
</code></pre>
<p>Note that we need to include all features defined in <code>FeatureType</code> to the object to match the type expectations.</p>
<p>If we want to allow a subset of the features as the key, we need to modify the index signature type with an “<code>?</code>” as an optional flag. Then, we could use the <code>FeatureConfig2</code> type for an object that only contains a subset of features.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> FeatureType = <span class="hljs-string">'profile'</span> | <span class="hljs-string">'notification'</span> | <span class="hljs-string">'reporting'</span>;

<span class="hljs-keyword">type</span> FeatureConfig2 = {
  [feature <span class="hljs-keyword">in</span> FeatureType]?: {
    enabled: <span class="hljs-built_in">boolean</span>;
    settings: Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">boolean</span>&gt;;
  }
}

<span class="hljs-keyword">const</span> subsetFeatures: FeatureConfig2 = {
  profile: {
    enabled: <span class="hljs-literal">true</span>,
    settings: {
      showPhoto: <span class="hljs-literal">true</span>,
      allowEdit: <span class="hljs-literal">false</span>,
    },
  }
};
</code></pre>
<h3 id="heading-index-signature-and-record-type">Index signature and Record type</h3>
<p>A common question about index signatures is “Why not use record type instead?“.</p>
<p>Record type defines an object type where we know the specific set of properties and their corresponding types. For example, below, the <code>UserRole</code> type restricts the keys to “admin”, “editor” or “viewer”.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> UserRole = <span class="hljs-string">"admin"</span> | <span class="hljs-string">"editor"</span> | <span class="hljs-string">"viewer"</span>;

<span class="hljs-keyword">type</span> UserPermissions = Record&lt;UserRole, <span class="hljs-built_in">boolean</span>&gt;;

<span class="hljs-keyword">const</span> permissions: UserPermissions = {
  admin: <span class="hljs-literal">true</span>,
  editor: <span class="hljs-literal">false</span>,
  viewer: <span class="hljs-literal">true</span>,
};
</code></pre>
<p>For the index signature, we don’t know the specific properties; we only know the general type of property types. Thus, the use case of the index signature is to model dynamic objects, and the record type can be used for known object types.</p>
<h2 id="heading-typescript-type-guards">Typescript Type Guards</h2>
<p>A type guard is an expression that performs a runtime check that guarantees the type in some scope. A typical application scenario for type guarding is to narrow the type scope of a union type. This is to ensure type safety, that is, to safely access specific properties or methods in a particular type of object during runtime.</p>
<h3 id="heading-typeof-type-guards"><code>typeof</code> type guards</h3>
<p>First, let’s introduce the more common <code>typeof</code> type of guards. The <code>typeof</code> operator can obtain the type of an object at runtime, and the operator returns the following possible values.</p>
<ul>
<li><p><code>"string"</code></p>
</li>
<li><p><code>"number"</code></p>
</li>
<li><p><code>"bigint"</code></p>
</li>
<li><p><code>"boolean"</code></p>
</li>
<li><p><code>"symbol"</code></p>
</li>
<li><p><code>"undefined"</code></p>
</li>
<li><p><code>"object"</code></p>
</li>
<li><p><code>"function"</code></p>
</li>
</ul>
<p>So using the <code>typeof</code> operator, we can get the actual value of a variable at runtime. Let’s take an example:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printId</span>(<span class="hljs-params">id: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span></span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> id === <span class="hljs-string">"string"</span>) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`ID: <span class="hljs-subst">${id.toUpperCase()}</span>`</span>);
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> id === <span class="hljs-string">"number"</span>) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`ID: <span class="hljs-subst">${id}</span>`</span>);
  }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729936539022/86b2a00b-395d-4507-81c8-70180f1298fe.webp" alt class="image--center mx-auto" /></p>
<p>So why use the <code>typeof</code> operator to narrow down the type of the <code>id</code> parameter? The main reason is to ensure type safety at runtime. For example, when the type of ID parameter is a numeric type, but we call the <code>id.toUpperCase()</code> method, a runtime exception will be thrown.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729936777117/f0405ad4-aea6-4d21-a446-db8ba8b0c831.webp" alt class="image--center mx-auto" /></p>
<p>In editors that support Typescript IntelliSense, you can access certain properties of the id parameter, and you can access common properties of the <code>string</code> and <code>number</code> types. Specifically, as shown in the picture below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729936971251/08f80205-b3ae-4cf5-805e-2683e7f27633.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-instanceof-type-guards"><code>instanceof</code> type guards</h3>
<p>Although the typeof operator can distinguish different types, if we want to determine whether an object is an instance of a certain class, so as to safely access the unique properties or methods on the instance, then the <code>typeof</code> operator can do nothing. For this requirement, we can use <code>instanceof</code> operator. Again, let’s take a concrete example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Shape {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">public</span> id: <span class="hljs-built_in">string</span></span>) {}
}

<span class="hljs-keyword">class</span> Circle <span class="hljs-keyword">extends</span> Shape {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-keyword">public</span> id: <span class="hljs-built_in">string</span>, 
    <span class="hljs-keyword">public</span> radius: <span class="hljs-built_in">number</span></span>) {
   <span class="hljs-built_in">super</span>(id);
  }
}

<span class="hljs-keyword">class</span> Square <span class="hljs-keyword">extends</span> Shape {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-keyword">public</span> id: <span class="hljs-built_in">string</span>, 
    <span class="hljs-keyword">public</span> sideLength: <span class="hljs-built_in">number</span></span>) {
      <span class="hljs-built_in">super</span>(id);
  }
}
</code></pre>
<p>In the above code, we define a <code>Shape</code> class and create two subclasses based on it. Next, we define a <code>printShapeInfo</code> function to print information about different shapes:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printShapeInfo</span>(<span class="hljs-params">shape: Shape</span>) </span>{
  <span class="hljs-keyword">if</span> (shape <span class="hljs-keyword">instanceof</span> Circle) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Circle's radius is: <span class="hljs-subst">${shape.radius}</span>`</span>);
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (shape <span class="hljs-keyword">instanceof</span> Square) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Square's sideLength is: <span class="hljs-subst">${shape.sideLength}</span>`</span>);
  }
}
</code></pre>
<h3 id="heading-in-type-guards">in type guards</h3>
<p>For the previous example of using the <code>instanceof</code> operator to implement type guards, we can also use the form of interfaces to describe the <code>Shape</code>, <code>Circle</code> and <code>Square</code> types.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Shape {
  id: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">interface</span> Circle <span class="hljs-keyword">extends</span> Shape {
  radius: <span class="hljs-built_in">number</span>;
}

<span class="hljs-keyword">interface</span> Square <span class="hljs-keyword">extends</span> Shape {
  sideLength: <span class="hljs-built_in">number</span>;
}
</code></pre>
<p>Because the type defined by the TypeScript interface does not generate the corresponding type after compilation, we cannot use the <code>instanceof</code> operator for type detection at runtime. To realize the functions of the <code>printShapeInfo</code> function, we can use the <code>in</code> operator, the specific implementation is as follows:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printShapeInfo</span>(<span class="hljs-params">shape: Shape</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-string">"radius"</span> <span class="hljs-keyword">in</span> shape) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Circle's radius is: <span class="hljs-subst">${shape.radius}</span>`</span>);
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-string">"sideLength"</span> <span class="hljs-keyword">in</span> shape) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Square's sideLength is: <span class="hljs-subst">${shape.sideLength}</span>`</span>);
  }
}
</code></pre>
<h3 id="heading-user-defined-type-guards">user-defined type guards</h3>
<p>To demonstrate user-defined type guards, let’s redefine the 3 types:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Shape {
  id: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">interface</span> Circle <span class="hljs-keyword">extends</span> Shape {
  radius: <span class="hljs-built_in">number</span>;
}

<span class="hljs-keyword">interface</span> Square <span class="hljs-keyword">extends</span> Shape {
  sideLength: <span class="hljs-built_in">number</span>;
}
</code></pre>
<p>After defining the types related to <code>Shape</code>, let’s define the user-defined type guards function:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isCircle</span>(<span class="hljs-params">shape: Shape</span>): <span class="hljs-title">shape</span> <span class="hljs-title">is</span> <span class="hljs-title">Circle</span> </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-string">"radius"</span> <span class="hljs-keyword">in</span> shape;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isSquare</span>(<span class="hljs-params">shape: Shape</span>): <span class="hljs-title">shape</span> <span class="hljs-title">is</span> <span class="hljs-title">Square</span> </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-string">"sideLength"</span> <span class="hljs-keyword">in</span> shape;
}
</code></pre>
<p>Compared with ordinary functions, custom type guard functions return type predicates. <code>shape is Circle</code> in the above code is the so-called type predicate. <strong>A predicate takes the form</strong> <code>parameterName is Type</code><strong>, where</strong> <code>parameterName</code> <strong>must be the name of a parameter from the current function signature.</strong> You can understand the role of the <code>isCircle</code> user-defined type guard function in this way. If the return value of the function is <code>true</code>, the type of the <code>shape</code> parameter is the <code>Circle</code> type.</p>
<p>Now that we have the <code>isCircle</code> and <code>isSquare</code> functions, we can use them in the <code>printShapeInfo</code> function like this:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printShapeInfo</span>(<span class="hljs-params">shape: Shape</span>) </span>{
  <span class="hljs-keyword">if</span> (isCircle(shape)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Circle's radius is: <span class="hljs-subst">${shape.radius}</span>`</span>);
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (isSquare(shape)) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Square's sideLength is: <span class="hljs-subst">${shape.sideLength}</span>`</span>);
  }
}
</code></pre>
<h3 id="heading-equality-narrowing-type-guards">equality narrowing type guards</h3>
<p>In addition to the 4 types of guarding methods described earlier, TypeScript also supports the use of <code>if/switch</code> statements and equality checks, such as, <code>===</code>, <code>!===</code>, <code>==</code> and <code>!=</code> operators to narrow the types of variables.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printValues</span>(<span class="hljs-params">a: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">string</span>[]</span>) </span>{
  <span class="hljs-keyword">if</span> (a === b) {
    <span class="hljs-built_in">console</span>.log(a.toUpperCase()); <span class="hljs-comment">// (parameter) a: string</span>
    <span class="hljs-built_in">console</span>.log(b.toUpperCase()); <span class="hljs-comment">// (parameter) b: string</span>
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(a); <span class="hljs-comment">// (parameter) a: string | number</span>
    <span class="hljs-built_in">console</span>.log(b); <span class="hljs-comment">// (parameter) b: string | string[]</span>
  }
}
</code></pre>
<p>In the above code, <code>printValues</code> function supports <code>a</code> and <code>b</code> 2 parameters, and their types are union types. When the <code>a===b</code>expression evaluates to <code>true</code>, the types of the parameters <code>a</code> and <code>b</code> will be narrowed to <code>string</code> type. Of course, using the <code>!==</code>operator can also be used to achieve type narrowing.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printValues2</span>(<span class="hljs-params">a: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">string</span>[]</span>) </span>{
  <span class="hljs-keyword">if</span> (a !== b) {
    <span class="hljs-built_in">console</span>.log(a); <span class="hljs-comment">// (parameter) a: string | number</span>
    <span class="hljs-built_in">console</span>.log(b); <span class="hljs-comment">// (parameter) b: string | string[]</span>
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(a.toLowerCase()); <span class="hljs-comment">// (parameter) a: string</span>
    <span class="hljs-built_in">console</span>.log(b.toLowerCase()); <span class="hljs-comment">// (parameter) b: string</span>
  }
}
</code></pre>
<h2 id="heading-the-dead-simple-typescript-trick-that-saved-me-15-hours-of-debugging-hell">The Dead Simple Typescript Trick That Saved Me 15+ Hours of Debugging Hell</h2>
<p>I had been chasing a bug for 6+ straight hours. The kind of bug that makes you question your career choices. Property errors in nested objects, type mismatch that made zero sense, and IntelliSense that was about as helpful as a chocolate teapot.</p>
<p><mark>Then I remembered the </mark> <code>satisfies</code> <mark> operator.</mark></p>
<p>One line of code. Fifteen minutes later, the bug was dead, buried, and I was shipping a coffee instead of contemplating a career change to organic farming.</p>
<p>If you are still fighting with TypeScript’s type system instead of making it work for you, this might just save your sanity, too.</p>
<h3 id="heading-the-problem-that-eating-your-time-and-you-dont-even-know-it">The Problem That Eating Your Time (And You Don’t Even Know It)</h3>
<p>Picture this: You are building a user management system. Nested objects everywhere. Complex types that make your brain hurt. And TypeScript? It’s being that friend who points out every tiny mistake but offers zero helpful suggestions.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> UserData = {
  username: <span class="hljs-built_in">string</span>;
  profile: {
    email: <span class="hljs-built_in">string</span>;
    preferences: {
      theme: <span class="hljs-string">'light'</span> | <span class="hljs-string">'dark'</span>;
      notifications: <span class="hljs-built_in">boolean</span>;
    };
  };
};
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// This looks fine, right? WRONG.</span>
<span class="hljs-keyword">const</span> user: UserData = {
  username: <span class="hljs-string">"john_doe"</span>,
  profile: {
    email: <span class="hljs-string">"john@example.com"</span>,
    preferences: {
      theme: <span class="hljs-string">"light"</span>,
      notifications: <span class="hljs-literal">true</span>,
    },
  },
};

<span class="hljs-comment">// Good luck accessing this without TypeScript having a meltdown</span>
<span class="hljs-built_in">console</span>.log(user.profile.preferences.theme); 
<span class="hljs-comment">// Sometimes works, sometimes doesn't. Depends on TypeScript's mood.</span>
</code></pre>
<p>Here’s what actually happens:</p>
<ul>
<li><p><mark>TypeScript loses track of your exact types</mark></p>
</li>
<li><p>IntelliSense becomes useless for nested objects</p>
</li>
<li><p>You get cryptic errors like “Property ‘theme’ does not exist on type…“</p>
</li>
<li><p>You waste hours adding explicit type assertions everywhere.</p>
</li>
<li><p>Your code looks like a Christmas tree of angle brackets, and as keywords</p>
</li>
</ul>
<p>Sound familiar? We have all been there.</p>
<h3 id="heading-the-satisfies-operator-your-new-best-friend"><strong>The</strong> <code>satisfies</code> Operator: Your New Best Friend</h3>
<p>The <code>satisfies</code> operator landed in TypeScript 4.9, and honestly? It’s a game-changer. The new satisfies lets us validate that the type of an expression matches some type, without changing the resulting type of that expression.</p>
<p>Here’s the magic:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> UserData = {
  username: <span class="hljs-built_in">string</span>;
  profile: {
    email: <span class="hljs-built_in">string</span>;
    preferences: {
      theme: <span class="hljs-string">'light'</span> | <span class="hljs-string">'dark'</span>;
      notifications: <span class="hljs-built_in">boolean</span>;
    };
  };
};
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// The same object, but with satisfies</span>
<span class="hljs-keyword">const</span> user = {
  username: <span class="hljs-string">"john_doe"</span>,
  profile: {
    email: <span class="hljs-string">"john@example.com"</span>,
    preferences: {
      theme: <span class="hljs-string">"light"</span>,
      notifications: <span class="hljs-literal">true</span>,
    },
  },
} satisfies UserData;

<span class="hljs-comment">// Now this just WORKS. Every. Single. Time.</span>
<span class="hljs-built_in">console</span>.log(user.profile.preferences.theme); <span class="hljs-comment">// "light" - TypeScript is happy</span>
</code></pre>
<p><strong>What just happened?</strong></p>
<ul>
<li><p>TypeScript validates your object structure ✅</p>
</li>
<li><p>BUT keeps the exact, precise types of your values ✅</p>
</li>
<li><p>IntelliSense works perfectly on nested properties ✅</p>
</li>
<li><p>Zero runtime overhead (it’s compile-time only) ✅</p>
</li>
</ul>
<p>It’s like having your cake and eating it too, except the cake is type safety and. you are not getting crumbs everywhere.</p>
<h3 id="heading-real-world-example-the-api-response-from-hell">Real-World Example: The API Response From Hell</h3>
<p>Last month, I was working with an API that returned this monstrosity:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> APIResponse = {
  data: {
    users: <span class="hljs-built_in">Array</span>&lt;{
      id: <span class="hljs-built_in">number</span>;
      details: {
        personal: {
          name: <span class="hljs-built_in">string</span>;
          age: <span class="hljs-built_in">number</span>;
        };
        settings: {
          theme: <span class="hljs-string">'light'</span> | <span class="hljs-string">'dark'</span> | <span class="hljs-string">'auto'</span>;
          language: <span class="hljs-built_in">string</span>;
        };
      };
    }&gt;;
    metadata: {
      total: <span class="hljs-built_in">number</span>;
      page: <span class="hljs-built_in">number</span>;
    };
  };
  status: <span class="hljs-string">'success'</span> | <span class="hljs-string">'error'</span>;
};
</code></pre>
<p><strong>Without</strong> <code>satisfies</code><strong>:</strong> I spent 3 hours debugging why <a target="_blank" href="http://response.data"><code>response.data</code></a><code>.users[0].details.settings.theme</code> was throwing type errors, even though the data was clearly there.</p>
<p><strong>With</strong> <code>satisfies</code><strong>:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> response = {
  data: {
    users: [
      {
        id: <span class="hljs-number">1</span>,
        details: {
          personal: {
            name: <span class="hljs-string">"Sarah Connor"</span>,
            age: <span class="hljs-number">35</span>,
          },
          settings: {
            theme: <span class="hljs-string">"dark"</span>,
            language: <span class="hljs-string">"en-US"</span>,
          },
        },
      },
    ],
    metadata: {
      total: <span class="hljs-number">1</span>,
      page: <span class="hljs-number">1</span>,
    },
  },
  status: <span class="hljs-string">"success"</span>,
} satisfies APIResponse;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// This just works. No drama. No fuss.</span>
<span class="hljs-keyword">const</span> userTheme = response.data.users[<span class="hljs-number">0</span>].details.settings.theme;
<span class="hljs-built_in">console</span>.log(userTheme); <span class="hljs-comment">// "dark"</span>
</code></pre>
<p>TypeScript knew exactly what I meant, IntelliSense worked perfectly, and I could access deeply nested properties without a single type assertion.</p>
<h3 id="heading-the-power-combo-satisfies-utility-types"><strong>The Power Combo:</strong> <code>satisfies</code> + Utility Types</h3>
<p>Want to level up even more? Combine <code>satisfies</code> with TypeScript's utility types. It's like adding rocket fuel to your development workflow.</p>
<p><strong>Example 1: Form Validation That Actually Works</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> FormData = {
  username: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
  password: <span class="hljs-built_in">string</span>;
  confirmPassword: <span class="hljs-built_in">string</span>;
  preferences: {
    newsletter: <span class="hljs-built_in">boolean</span>;
    updates: <span class="hljs-built_in">boolean</span>;
  };
};
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// Only validate the fields the user has filled</span>
<span class="hljs-keyword">const</span> partialForm = {
  username: <span class="hljs-string">"awesome_dev"</span>,
  email: <span class="hljs-string">"dev@example.com"</span>,
  preferences: {
    newsletter: <span class="hljs-literal">true</span>,
    updates: <span class="hljs-literal">false</span>,
  },
} satisfies Partial&lt;FormData&gt;;
<span class="hljs-comment">// No complaints about missing password fields</span>
<span class="hljs-comment">// Perfect for multi-step forms!</span>
</code></pre>
<p><strong>Example 2: Configuration Objects Made Simple</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> AppConfig = {
  database: { host: <span class="hljs-built_in">string</span>; port: <span class="hljs-built_in">number</span> };
  cache: { redis: <span class="hljs-built_in">string</span>; ttl: <span class="hljs-built_in">number</span> };
  features: { darkMode: <span class="hljs-built_in">boolean</span>; analytics: <span class="hljs-built_in">boolean</span> };
};
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// Pick only what you need for development</span>
<span class="hljs-keyword">const</span> devConfig = {
  database: { host: <span class="hljs-string">"localhost"</span>, port: <span class="hljs-number">5432</span> },
  features: { darkMode: <span class="hljs-literal">true</span>, analytics: <span class="hljs-literal">false</span> },
} satisfies Pick&lt;AppConfig, <span class="hljs-string">'database'</span> | <span class="hljs-string">'features'</span>&gt;;
</code></pre>
<p>This approach has become central to how I handle complex configurations in my client projects.</p>
<h2 id="heading-5-very-useful-tricks-for-typescript-typeof-operator">5 Very Useful Tricks for TypeScript Typeof Operator</h2>
<p>In JavaScript, you can get the type of a variable through <code>typeof</code> operator, do you know what the <code>typeof</code> operator is used in Typescript? I will introduce 5 common application scenarios of the <code>typeof</code> operator, which you may use in future projects.</p>
<h3 id="heading-get-the-type-of-object">Get the type of object</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729159021341/68493043-e6d7-446d-a1f1-0f0deee81d80.webp" alt class="image--center mx-auto" /></p>
<p>The <code>man</code> object is a regular JavaScript object. In Typescript, you can use an interface or type to define the type of object. With this object type, you can use TypeScript’s built-in utility types, such as Partial, Required, Pick, or Readonly, to handle object types to meet different needs.</p>
<p>For simple objects, this may not be a big deal. But for large, complex objects with deeper nesting levels, manually defining their types can be mind-numbing. To solve this problem, you can use <code>typeof</code> operator.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">type</span> Person = typeof man;
<span class="hljs-built_in">type</span> Address = Person[<span class="hljs-string">"address"</span>];
</code></pre>
<p>Compared to manually defining the type before. It becomes much easier to use the <code>typeof</code> operator. <code>Person["address"]</code> is an indexed access type used to look up a specific property (address) on another type (Person type).</p>
<h3 id="heading-get-a-type-that-represents-all-enum-keys-as-strings">Get a Type That Represents All Enum Keys as Strings.</h3>
<p>In Typescript, enum types are special types that get combined into regular JavaScript objects.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729160025557/191e278a-d851-42d1-aac3-06c06867740c.webp" alt class="image--center mx-auto" /></p>
<p>Therefore, you can also use the <code>typeof</code> operator on enum types. But this is often not of much practical use, and when dealing with enum types, it is usually combined with the <code>keyof</code> operator.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729160412880/df8af035-171a-42d2-bc5e-ed0547857d22.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-get-the-type-of-the-function-object">Get The Type of The Function Object</h3>
<p>There is another more common scenario in which the typeof operator is used in your work. After obtaining the corresponding function type, you can continue to use Typescript’s built-in ReturnType and Parameters utility types to obtain the function’s return value type and parameter type, respectively.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729160893216/1d87c1ac-83e4-4947-80a5-9d9ade741c3f.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-get-the-type-of-the-class-object">Get the Type of the Class Object</h3>
<p>Since the typeof operator can handle the function object, can it handle Class objects? The answer is yes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729161081568/a55ad81a-559f-4e04-9c0c-fe9b411bb206.webp" alt class="image--center mx-auto" /></p>
<p>In the above code, <code>createPoint</code> is a factory function that creates an instance of the Point class. Through the typeof operator, you can obtain the corresponding construct signature of the Point class, so as to realize the corresponding type verification. When defining the parameter type of a Constructor, if the typeof operator is not used, the following error message will appear:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729162468475/5e42bb8e-42a9-4c91-8aa6-8a99d6a132d4.webp" alt class="image--center mx-auto" /></p>
<h3 id="heading-get-a-more-precise-type">Get a More Precise Type</h3>
<p>When using the typeof operator, if you want to get a more precise type, then you combine it with the cost assertion introduced in Typescript version 3.4. This is used in the following way.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729162900810/81755be5-59a9-4b1e-9cc7-58a73e5460b9.webp" alt class="image--center mx-auto" /></p>
<p>As you see in the above figure, after using the cost assertion and then using the typeof operator, you can obtain a more precise type.</p>
<h2 id="heading-advanced-typescript-patterns">Advanced Typescript Patterns</h2>
<p>TypeScript has revolutionized JavaScript development by bringing strong typing and advanced patterns to the ecosystem. In this section, we will explore advanced Typescript patterns that not only make your codebase more robust but also improve your JavaScript development skills.</p>
<h3 id="heading-anders-hejlsbergs-type-first-code-second-philosophy">Anders Hejlsberg’s “Type First, Code Second” Philosophy</h3>
<p>The creator of TypeScript himself advocates for designing your types before writing the implementation. Anders often emphasizes: <em>“Types are documentation that never lies.”</em></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Instead of this messy approach</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processUser</span>(<span class="hljs-params">user: <span class="hljs-built_in">any</span></span>) </span>{
  <span class="hljs-keyword">if</span> (user.name &amp;&amp; user.email) {
    <span class="hljs-comment">// Hope for the best 🤞</span>
    <span class="hljs-keyword">return</span> user.name.toUpperCase();
  }
}

<span class="hljs-comment">// Anders' approach: Define the contract first</span>
<span class="hljs-keyword">interface</span> User {
  <span class="hljs-keyword">readonly</span> id: <span class="hljs-built_in">string</span>;
  name: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
  preferences?: UserPreferences;
}

<span class="hljs-keyword">interface</span> UserPreferences {
  theme: <span class="hljs-string">'light'</span> | <span class="hljs-string">'dark'</span>;
  notifications: <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">processUser</span>(<span class="hljs-params">user: User</span>): <span class="hljs-title">string</span> </span>{
  <span class="hljs-comment">// TypeScript guarantees these properties exist</span>
  <span class="hljs-keyword">return</span> user.name.toUpperCase();
}
</code></pre>
<p>This pattern alone cut my debugging time by 60%. When you define types upfront, TypeScript becomes your pair programmer, catching errors before they hit production.</p>
<h3 id="heading-matt-pococks-utility-type-mastery">Matt Pocock’s Utility Type Mastery</h3>
<p>Matt Pocock, the TypeScript educator extraordinaire, is famous for his utility type patterns that make complex scenarios simple. His favorite productivity hack? <strong>Template literal types for API routes:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Matt's genius pattern for type-safe API routes</span>
<span class="hljs-keyword">type</span> APIRoutes = 
  | <span class="hljs-string">'/users'</span>
  | <span class="hljs-string">'/users/:id'</span>
  | <span class="hljs-string">'/products'</span>
  | <span class="hljs-string">'/products/:id/reviews'</span>;

<span class="hljs-keyword">type</span> ExtractParams&lt;T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">string</span>&gt; = T <span class="hljs-keyword">extends</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">string</span>}</span>:<span class="hljs-subst">${infer Param}</span>/<span class="hljs-subst">${infer Rest}</span>`</span>
  ? { [K <span class="hljs-keyword">in</span> Param]: <span class="hljs-built_in">string</span> } &amp; ExtractParams&lt;<span class="hljs-string">`/<span class="hljs-subst">${Rest}</span>`</span>&gt;
  : T <span class="hljs-keyword">extends</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">string</span>}</span>:<span class="hljs-subst">${infer Param}</span>`</span>
  ? { [K <span class="hljs-keyword">in</span> Param]: <span class="hljs-built_in">string</span> }
  : {};

<span class="hljs-comment">// Now your API calls are bulletproof</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">apiCall</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> <span class="hljs-title">APIRoutes</span>&gt;(<span class="hljs-params">
  route: T,
  params: ExtractParams&lt;T&gt;
</span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">any</span>&gt; </span>{
  <span class="hljs-comment">// Implementation with full type safety</span>
}

<span class="hljs-comment">// Usage - TypeScript knows exactly what params you need!</span>
apiCall(<span class="hljs-string">'/users/:id'</span>, { id: <span class="hljs-string">'123'</span> }); <span class="hljs-comment">// ✅</span>
apiCall(<span class="hljs-string">'/users/:id'</span>, { userId: <span class="hljs-string">'123'</span> }); <span class="hljs-comment">// ❌ Error!</span>
</code></pre>
<p>This connects perfectly with what I wrote about in my previous article on <a target="_blank" href="https://medium.com/@mohantaankit2002/using-typescript-utility-types-for-clean-and-scalable-code-in-large-projects-e941b776eed1">using TypeScript utility types for clean and scalable code</a>. The combination of these patterns can transform how you handle large codebases.</p>
<h3 id="heading-kent-c-dodds-make-invalid-states-impossible-pattern">Kent C. Dodds’ “Make Invalid States Impossible” Pattern</h3>
<p>Kent’s philosophy is brilliant: instead of handling invalid states, design your types so they can’t exist in the first place.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Bad: Multiple possible invalid states</span>
<span class="hljs-keyword">interface</span> LoadingState {
  isLoading: <span class="hljs-built_in">boolean</span>;
  error: <span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>;
  data: <span class="hljs-built_in">any</span> | <span class="hljs-literal">null</span>;
}

<span class="hljs-comment">// Kent's approach: Discriminated unions make invalid states impossible</span>
<span class="hljs-keyword">type</span> AsyncState&lt;T&gt; = 
  | { status: <span class="hljs-string">'idle'</span> }
  | { status: <span class="hljs-string">'loading'</span> }
  | { status: <span class="hljs-string">'success'</span>; data: T }
  | { status: <span class="hljs-string">'error'</span>; error: <span class="hljs-built_in">string</span> };

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useAsyncData</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params"></span>): <span class="hljs-title">AsyncState</span>&lt;<span class="hljs-title">T</span>&gt; </span>{
  <span class="hljs-comment">// Now you can't accidentally have loading=true AND data present</span>
  <span class="hljs-comment">// TypeScript enforces logical consistency</span>
}

<span class="hljs-comment">// Usage becomes bulletproof</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfile</span>(<span class="hljs-params">{ asyncState }: { asyncState: AsyncState&lt;User&gt; }</span>) </span>{
  <span class="hljs-keyword">switch</span> (asyncState.status) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'loading'</span>:
      <span class="hljs-keyword">return</span> &lt;Spinner /&gt;; <span class="hljs-comment">// asyncState.data doesn't exist here!</span>
    <span class="hljs-keyword">case</span> <span class="hljs-string">'success'</span>:
      <span class="hljs-keyword">return</span> &lt;div&gt;{asyncState.data.name}&lt;<span class="hljs-regexp">/div&gt;; /</span><span class="hljs-regexp">/ data is guaranteed!
    case 'error':
      return &lt;div&gt;Error: {asyncState.error}&lt;/</span>div&gt;; <span class="hljs-comment">// error is guaranteed!</span>
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> &lt;div&gt;No data yet&lt;/div&gt;;
  }
}
</code></pre>
<p>This pattern eliminated an entire class of bugs from my applications. No more checking if loading is true while data also exists — TypeScript makes it impossible.</p>
<h3 id="heading-josh-goldbergs-conditional-type-wizardry">Josh Goldberg’s Conditional Type Wizardry</h3>
<p>Josh Goldberg, author of “Learning TypeScript,” teaches advanced conditional patterns that feel like magic:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Josh's pattern for smart function overloads</span>
<span class="hljs-keyword">type</span> SmartFunction&lt;T&gt; = T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">string</span> 
  ? <span class="hljs-function">(<span class="hljs-params">input: T</span>) =&gt;</span> <span class="hljs-built_in">string</span>
  : T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">number</span>
  ? <span class="hljs-function">(<span class="hljs-params">input: T</span>) =&gt;</span> <span class="hljs-built_in">number</span>
  : T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">boolean</span>
  ? <span class="hljs-function">(<span class="hljs-params">input: T</span>) =&gt;</span> <span class="hljs-built_in">string</span>
  : <span class="hljs-built_in">never</span>;

<span class="hljs-comment">// One function, multiple behaviors based on input type</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">smartProcess</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> <span class="hljs-title">string</span> | <span class="hljs-title">number</span> | <span class="hljs-title">boolean</span>&gt;(<span class="hljs-params">input: T</span>): <span class="hljs-title">ReturnType</span>&lt;<span class="hljs-title">SmartFunction</span>&lt;<span class="hljs-title">T</span>&gt;&gt; </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> input === <span class="hljs-string">'string'</span>) {
    <span class="hljs-keyword">return</span> input.toUpperCase() <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>;
  }
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> input === <span class="hljs-string">'number'</span>) {
    <span class="hljs-keyword">return</span> input * <span class="hljs-number">2</span> <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>;
  }
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> input === <span class="hljs-string">'boolean'</span>) {
    <span class="hljs-keyword">return</span> input.toString() <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>;
  }
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Invalid input type'</span>);
}

<span class="hljs-comment">// Usage - TypeScript infers return types perfectly</span>
<span class="hljs-keyword">const</span> result1 = smartProcess(<span class="hljs-string">"hello"</span>); <span class="hljs-comment">// string</span>
<span class="hljs-keyword">const</span> result2 = smartProcess(<span class="hljs-number">42</span>); <span class="hljs-comment">// number  </span>
<span class="hljs-keyword">const</span> result3 = smartProcess(<span class="hljs-literal">true</span>); <span class="hljs-comment">// string</span>
</code></pre>
<h3 id="heading-marius-schulzs-brand-types-for-extra-safety">Marius Schulz’s “Brand Types” for Extra Safety</h3>
<p>Marius introduced me to branded types — a pattern that prevents subtle bugs by making similar types incompatible:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Create branded types for extra safety</span>
<span class="hljs-keyword">type</span> UserId = <span class="hljs-built_in">string</span> &amp; { <span class="hljs-keyword">readonly</span> brand: unique symbol };
<span class="hljs-keyword">type</span> ProductId = <span class="hljs-built_in">string</span> &amp; { <span class="hljs-keyword">readonly</span> brand: unique symbol };

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createUserId</span>(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">UserId</span> </span>{
  <span class="hljs-keyword">return</span> id <span class="hljs-keyword">as</span> UserId;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createProductId</span>(<span class="hljs-params">id: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">ProductId</span> </span>{
  <span class="hljs-keyword">return</span> id <span class="hljs-keyword">as</span> ProductId;
}

<span class="hljs-comment">// Now these functions can't be called with wrong IDs</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUser</span>(<span class="hljs-params">id: UserId</span>): <span class="hljs-title">User</span> </span>{ <span class="hljs-comment">/* ... */</span> }
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProduct</span>(<span class="hljs-params">id: ProductId</span>): <span class="hljs-title">Product</span> </span>{ <span class="hljs-comment">/* ... */</span> }

<span class="hljs-keyword">const</span> userId = createUserId(<span class="hljs-string">"user-123"</span>);
<span class="hljs-keyword">const</span> productId = createProductId(<span class="hljs-string">"prod-456"</span>);

getUser(userId); <span class="hljs-comment">// ✅</span>
getUser(productId); <span class="hljs-comment">// ❌ Error! Can't use ProductId as UserId</span>
</code></pre>
<p>This pattern has saved me countless times from passing wrong IDs to functions.</p>
<h3 id="heading-type-level-programming">Type-Level Programming</h3>
<p><strong>Conditional Types</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Advanced conditional type pattern</span>
<span class="hljs-keyword">type</span> IsArray&lt;T&gt; = T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">Array</span>&lt;<span class="hljs-built_in">any</span>&gt; ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;
<span class="hljs-keyword">type</span> IsString&lt;T&gt; = T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">string</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;

<span class="hljs-comment">// Practical example: API response handler</span>
<span class="hljs-keyword">type</span> ApiResponse&lt;T&gt; = {
    data: T;
    status: <span class="hljs-built_in">number</span>;
    message: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">type</span> ExtractData&lt;T&gt; = T <span class="hljs-keyword">extends</span> ApiResponse&lt;infer U&gt; ? U : <span class="hljs-built_in">never</span>;

<span class="hljs-comment">// Usage example</span>
<span class="hljs-keyword">interface</span> UserData {
    id: <span class="hljs-built_in">number</span>;
    name: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">type</span> UserApiResponse = ApiResponse&lt;UserData&gt;;
<span class="hljs-keyword">type</span> ExtractedUserData = ExtractData&lt;UserApiResponse&gt;; <span class="hljs-comment">// Returns UserData type</span>
</code></pre>
<p><strong>Template Literal Types</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Define valid HTTP methods</span>
<span class="hljs-keyword">type</span> HttpMethod = <span class="hljs-string">'GET'</span> | <span class="hljs-string">'POST'</span> | <span class="hljs-string">'PUT'</span> | <span class="hljs-string">'DELETE'</span>;
<span class="hljs-keyword">type</span> ApiEndpoint = <span class="hljs-string">'/users'</span> | <span class="hljs-string">'/posts'</span> | <span class="hljs-string">'/comments'</span>;

<span class="hljs-comment">// Create API route types</span>
<span class="hljs-keyword">type</span> ApiRoute = <span class="hljs-string">`<span class="hljs-subst">${HttpMethod}</span> <span class="hljs-subst">${ApiEndpoint}</span>`</span>;

<span class="hljs-comment">// Validate routes at compile time</span>
<span class="hljs-keyword">const</span> validRoute: ApiRoute = <span class="hljs-string">'GET /users'</span>;     <span class="hljs-comment">// ✅ Valid</span>
<span class="hljs-keyword">const</span> invalidRoute: ApiRoute = <span class="hljs-string">'PATCH /users'</span>;  <span class="hljs-comment">// ❌ Type error</span>
</code></pre>
<h3 id="heading-advanced-generic-patterns">Advanced Generic Patterns</h3>
<p><strong>Factory with Generic Constraints</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> HasId {
    id: <span class="hljs-built_in">number</span>;
}

<span class="hljs-keyword">interface</span> HasTimestamps {
    createdAt: <span class="hljs-built_in">Date</span>;
    updatedAt: <span class="hljs-built_in">Date</span>;
}

<span class="hljs-comment">// Generic factory with constraints</span>
<span class="hljs-keyword">class</span> EntityFactory&lt;T <span class="hljs-keyword">extends</span> HasId &amp; HasTimestamps&gt; {
    create(data: Omit&lt;T, keyof HasTimestamps&gt;): T {
        <span class="hljs-keyword">return</span> {
            ...data,
            createdAt: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
            updatedAt: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>()
        } <span class="hljs-keyword">as</span> T;
    }

    update(entity: T, data: Partial&lt;Omit&lt;T, keyof HasId | keyof HasTimestamps&gt;&gt;): T {
        <span class="hljs-keyword">return</span> {
            ...entity,
            ...data,
            updatedAt: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>()
        };
    }
}

<span class="hljs-comment">// Usage example</span>
<span class="hljs-keyword">interface</span> User <span class="hljs-keyword">extends</span> HasId, HasTimestamps {
    id: <span class="hljs-built_in">number</span>;
    name: <span class="hljs-built_in">string</span>;
    email: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> userFactory = <span class="hljs-keyword">new</span> EntityFactory&lt;User&gt;();
<span class="hljs-keyword">const</span> user = userFactory.create({ id: <span class="hljs-number">1</span>, name: <span class="hljs-string">'John'</span>, email: <span class="hljs-string">'john@example.com'</span> });
</code></pre>
<p><strong>Type-Safe Event Emitter</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> EventMap = {
    <span class="hljs-string">'user:login'</span>: { userId: <span class="hljs-built_in">string</span>; timestamp: <span class="hljs-built_in">number</span> };
    <span class="hljs-string">'user:logout'</span>: { userId: <span class="hljs-built_in">string</span>; timestamp: <span class="hljs-built_in">number</span> };
    <span class="hljs-string">'error'</span>: { message: <span class="hljs-built_in">string</span>; code: <span class="hljs-built_in">number</span> };
}

<span class="hljs-keyword">class</span> TypedEventEmitter&lt;T <span class="hljs-keyword">extends</span> Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">any</span>&gt;&gt; {
    <span class="hljs-keyword">private</span> listeners: Partial&lt;Record&lt;keyof T, <span class="hljs-built_in">Function</span>[]&gt;&gt; = {};

    on&lt;K <span class="hljs-keyword">extends</span> keyof T&gt;(event: K, callback: <span class="hljs-function">(<span class="hljs-params">data: T[K]</span>) =&gt;</span> <span class="hljs-built_in">void</span>) {
        <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.listeners[event]) {
            <span class="hljs-built_in">this</span>.listeners[event] = [];
        }
        <span class="hljs-built_in">this</span>.listeners[event]?.push(callback);
    }

    emit&lt;K <span class="hljs-keyword">extends</span> keyof T&gt;(event: K, data: T[K]) {
        <span class="hljs-built_in">this</span>.listeners[event]?.forEach(<span class="hljs-function"><span class="hljs-params">callback</span> =&gt;</span> callback(data));
    }
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">const</span> emitter = <span class="hljs-keyword">new</span> TypedEventEmitter&lt;EventMap&gt;();

emitter.on(<span class="hljs-string">'user:login'</span>, <span class="hljs-function">(<span class="hljs-params">{ userId, timestamp }</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`User <span class="hljs-subst">${userId}</span> logged in at <span class="hljs-subst">${timestamp}</span>`</span>);
});

<span class="hljs-comment">// Type-safe emit</span>
emitter.emit(<span class="hljs-string">'user:login'</span>, { 
    userId: <span class="hljs-string">'123'</span>, 
    timestamp: <span class="hljs-built_in">Date</span>.now() 
});
</code></pre>
<h3 id="heading-discriminated-unions">Discriminated Unions</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">// Define possible states with discriminated union</span>
<span class="hljs-keyword">type</span> AsyncState&lt;T, E = <span class="hljs-built_in">Error</span>&gt; = 
    | { status: <span class="hljs-string">'idle'</span> }
    | { status: <span class="hljs-string">'loading'</span> }
    | { status: <span class="hljs-string">'success'</span>; data: T }
    | { status: <span class="hljs-string">'error'</span>; error: E };

<span class="hljs-comment">// Generic async data handler</span>
<span class="hljs-keyword">class</span> AsyncData&lt;T, E = <span class="hljs-built_in">Error</span>&gt; {
    <span class="hljs-keyword">private</span> state: AsyncState&lt;T, E&gt; = { status: <span class="hljs-string">'idle'</span> };

    setState(newState: AsyncState&lt;T, E&gt;) {
        <span class="hljs-built_in">this</span>.state = newState;
        <span class="hljs-built_in">this</span>.render();
    }

    render() {
        <span class="hljs-keyword">switch</span> (<span class="hljs-built_in">this</span>.state.status) {
            <span class="hljs-keyword">case</span> <span class="hljs-string">'idle'</span>:
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Waiting to start...'</span>);
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> <span class="hljs-string">'loading'</span>:
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Loading...'</span>);
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> <span class="hljs-string">'success'</span>:
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Data:'</span>, <span class="hljs-built_in">this</span>.state.data);
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> <span class="hljs-string">'error'</span>:
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error:'</span>, <span class="hljs-built_in">this</span>.state.error);
                <span class="hljs-keyword">break</span>;
        }
    }
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">interface</span> UserProfile {
    id: <span class="hljs-built_in">string</span>;
    name: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> userProfile = <span class="hljs-keyword">new</span> AsyncData&lt;UserProfile&gt;();
</code></pre>
<h3 id="heading-utility-types-deep-dive">Utility Types Deep Dive</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">// Make all properties optional and nullable</span>
<span class="hljs-keyword">type</span> Nullable&lt;T&gt; = { [P <span class="hljs-keyword">in</span> keyof T]: T[P] | <span class="hljs-literal">null</span> };

<span class="hljs-comment">// Make specific properties required</span>
<span class="hljs-keyword">type</span> RequiredProps&lt;T, K <span class="hljs-keyword">extends</span> keyof T&gt; = T &amp; { [P <span class="hljs-keyword">in</span> K]-?: T[P] };

<span class="hljs-comment">// Deep partial type</span>
<span class="hljs-keyword">type</span> DeepPartial&lt;T&gt; = {
    [P <span class="hljs-keyword">in</span> keyof T]?: T[P] <span class="hljs-keyword">extends</span> <span class="hljs-built_in">object</span> ? DeepPartial&lt;T[P]&gt; : T[P];
};

<span class="hljs-comment">// Usage example</span>
<span class="hljs-keyword">interface</span> Config {
    api: {
        baseUrl: <span class="hljs-built_in">string</span>;
        timeout: <span class="hljs-built_in">number</span>;
        headers: {
            authorization: <span class="hljs-built_in">string</span>;
            contentType: <span class="hljs-built_in">string</span>;
        };
    };
    cache: {
        enabled: <span class="hljs-built_in">boolean</span>;
        ttl: <span class="hljs-built_in">number</span>;
    };
}

<span class="hljs-keyword">type</span> PartialConfig = DeepPartial&lt;Config&gt;;

<span class="hljs-keyword">const</span> config: PartialConfig = {
    api: {
        baseUrl: <span class="hljs-string">'https://api.example.com'</span>,
        headers: {
            authorization: <span class="hljs-string">'Bearer token'</span>
        }
    }
};
</code></pre>
<h3 id="heading-factory-pattern">Factory Pattern</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">// Abstract product interfaces</span>
<span class="hljs-keyword">interface</span> Button {
    render(): <span class="hljs-built_in">void</span>;
    onClick(): <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">interface</span> Input {
    render(): <span class="hljs-built_in">void</span>;
    getValue(): <span class="hljs-built_in">string</span>;
}

<span class="hljs-comment">// Abstract factory interface</span>
<span class="hljs-keyword">interface</span> UIFactory {
    createButton(): Button;
    createInput(): Input;
}

<span class="hljs-comment">// Concrete implementations</span>
<span class="hljs-keyword">class</span> MaterialButton <span class="hljs-keyword">implements</span> Button {
    render() { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Rendering Material button'</span>); }
    onClick() { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Material button clicked'</span>); }
}

<span class="hljs-keyword">class</span> MaterialInput <span class="hljs-keyword">implements</span> Input {
    render() { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Rendering Material input'</span>); }
    getValue() { <span class="hljs-keyword">return</span> <span class="hljs-string">'Material input value'</span>; }
}

<span class="hljs-keyword">class</span> MaterialUIFactory <span class="hljs-keyword">implements</span> UIFactory {
    createButton(): Button {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> MaterialButton();
    }
    createInput(): Input {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> MaterialInput();
    }
}

<span class="hljs-comment">// Usage with dependency injection</span>
<span class="hljs-keyword">class</span> Form {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> factory: UIFactory</span>) {}

    render() {
        <span class="hljs-keyword">const</span> button = <span class="hljs-built_in">this</span>.factory.createButton();
        <span class="hljs-keyword">const</span> input = <span class="hljs-built_in">this</span>.factory.createInput();
        button.render();
        input.render();
    }
}
</code></pre>
<h3 id="heading-state-management-patterns">State Management Patterns</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">// Action types with discriminated unions</span>
<span class="hljs-keyword">type</span> Action =
    | { <span class="hljs-keyword">type</span>: <span class="hljs-string">'ADD_TODO'</span>; payload: { text: <span class="hljs-built_in">string</span> } }
    | { <span class="hljs-keyword">type</span>: <span class="hljs-string">'TOGGLE_TODO'</span>; payload: { id: <span class="hljs-built_in">number</span> } }
    | { <span class="hljs-keyword">type</span>: <span class="hljs-string">'DELETE_TODO'</span>; payload: { id: <span class="hljs-built_in">number</span> } };

<span class="hljs-keyword">interface</span> Todo {
    id: <span class="hljs-built_in">number</span>;
    text: <span class="hljs-built_in">string</span>;
    completed: <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-keyword">interface</span> State {
    todos: Todo[];
    loading: <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-comment">// Type-safe reducer</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reducer</span>(<span class="hljs-params">state: State, action: Action</span>): <span class="hljs-title">State</span> </span>{
    <span class="hljs-keyword">switch</span> (action.type) {
        <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_TODO'</span>:
            <span class="hljs-keyword">return</span> {
                ...state,
                todos: [...state.todos, {
                    id: <span class="hljs-built_in">Date</span>.now(),
                    text: action.payload.text,
                    completed: <span class="hljs-literal">false</span>
                }]
            };
        <span class="hljs-keyword">case</span> <span class="hljs-string">'TOGGLE_TODO'</span>:
            <span class="hljs-keyword">return</span> {
                ...state,
                todos: state.todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
                    todo.id === action.payload.id
                        ? { ...todo, completed: !todo.completed }
                        : todo
                )
            };
        <span class="hljs-keyword">case</span> <span class="hljs-string">'DELETE_TODO'</span>:
            <span class="hljs-keyword">return</span> {
                ...state,
                todos: state.todos.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> todo.id !== action.payload.id)
            };
    }
}
</code></pre>
<h3 id="heading-builder-patterns">Builder Patterns</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> QueryBuilder&lt;T&gt; {
    <span class="hljs-keyword">private</span> query: Partial&lt;T&gt; = {};
    <span class="hljs-keyword">private</span> conditions: <span class="hljs-built_in">Array</span>&lt;<span class="hljs-function">(<span class="hljs-params">item: T</span>) =&gt;</span> <span class="hljs-built_in">boolean</span>&gt; = [];

    where&lt;K <span class="hljs-keyword">extends</span> keyof T&gt;(key: K, value: T[K]): <span class="hljs-built_in">this</span> {
        <span class="hljs-built_in">this</span>.query[key] = value;
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
    }

    whereIn&lt;K <span class="hljs-keyword">extends</span> keyof T&gt;(key: K, values: T[K][]): <span class="hljs-built_in">this</span> {
        <span class="hljs-built_in">this</span>.conditions.push(<span class="hljs-function">(<span class="hljs-params">item: T</span>) =&gt;</span> 
            values.includes(item[key])
        );
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
    }

    build(): <span class="hljs-function">(<span class="hljs-params">item: T</span>) =&gt;</span> <span class="hljs-built_in">boolean</span> {
        <span class="hljs-keyword">const</span> query = <span class="hljs-built_in">this</span>.query;
        <span class="hljs-keyword">const</span> conditions = <span class="hljs-built_in">this</span>.conditions;

        <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">item: T</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> matchesQuery = <span class="hljs-built_in">Object</span>.entries(query).every(
                <span class="hljs-function">(<span class="hljs-params">[key, value]</span>) =&gt;</span> item[key <span class="hljs-keyword">as</span> keyof T] === value
            );

            <span class="hljs-keyword">const</span> matchesConditions = conditions.every(
                <span class="hljs-function"><span class="hljs-params">condition</span> =&gt;</span> condition(item)
            );

            <span class="hljs-keyword">return</span> matchesQuery &amp;&amp; matchesConditions;
        };
    }
}

<span class="hljs-comment">// Usage example</span>
<span class="hljs-keyword">interface</span> User {
    id: <span class="hljs-built_in">number</span>;
    name: <span class="hljs-built_in">string</span>;
    age: <span class="hljs-built_in">number</span>;
    role: <span class="hljs-string">'admin'</span> | <span class="hljs-string">'user'</span>;
}

<span class="hljs-keyword">const</span> query = <span class="hljs-keyword">new</span> QueryBuilder&lt;User&gt;()
    .where(<span class="hljs-string">'role'</span>, <span class="hljs-string">'admin'</span>)
    .whereIn(<span class="hljs-string">'age'</span>, [<span class="hljs-number">25</span>, <span class="hljs-number">30</span>, <span class="hljs-number">35</span>])
    .build();

<span class="hljs-keyword">const</span> users: User[] = [
    { id: <span class="hljs-number">1</span>, name: <span class="hljs-string">'John'</span>, age: <span class="hljs-number">30</span>, role: <span class="hljs-string">'admin'</span> },
    { id: <span class="hljs-number">2</span>, name: <span class="hljs-string">'Jane'</span>, age: <span class="hljs-number">25</span>, role: <span class="hljs-string">'user'</span> }
];

<span class="hljs-keyword">const</span> results = users.filter(query);
</code></pre>
<h3 id="heading-type-safe-api-client">Type-Safe API Client</h3>
<pre><code class="lang-typescript"><span class="hljs-comment">// API endpoints definition</span>
<span class="hljs-keyword">interface</span> ApiEndpoints {
    <span class="hljs-string">'/users'</span>: {
        GET: {
            response: User[];
            query: { role?: <span class="hljs-built_in">string</span> };
        };
        POST: {
            body: Omit&lt;User, <span class="hljs-string">'id'</span>&gt;;
            response: User;
        };
    };
    <span class="hljs-string">'/users/:id'</span>: {
        GET: {
            params: { id: <span class="hljs-built_in">string</span> };
            response: User;
        };
        PUT: {
            params: { id: <span class="hljs-built_in">string</span> };
            body: Partial&lt;User&gt;;
            response: User;
        };
    };
}

<span class="hljs-comment">// Type-safe API client</span>
<span class="hljs-keyword">class</span> ApiClient {
    <span class="hljs-keyword">async</span> get&lt;
        Path <span class="hljs-keyword">extends</span> keyof ApiEndpoints,
        Method <span class="hljs-keyword">extends</span> keyof ApiEndpoints[Path],
        Endpoint <span class="hljs-keyword">extends</span> ApiEndpoints[Path][Method]
    &gt;(
        path: Path,
        config?: {
            params?: Endpoint <span class="hljs-keyword">extends</span> { params: <span class="hljs-built_in">any</span> } ? Endpoint[<span class="hljs-string">'params'</span>] : <span class="hljs-built_in">never</span>;
            query?: Endpoint <span class="hljs-keyword">extends</span> { query: <span class="hljs-built_in">any</span> } ? Endpoint[<span class="hljs-string">'query'</span>] : <span class="hljs-built_in">never</span>;
        }
    ): <span class="hljs-built_in">Promise</span>&lt;Endpoint <span class="hljs-keyword">extends</span> { response: <span class="hljs-built_in">any</span> } ? Endpoint[<span class="hljs-string">'response'</span>] : <span class="hljs-built_in">never</span>&gt; {
        <span class="hljs-comment">// Implementation</span>
        <span class="hljs-keyword">return</span> {} <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>;
    }

    <span class="hljs-keyword">async</span> post&lt;
        Path <span class="hljs-keyword">extends</span> keyof ApiEndpoints,
        Method <span class="hljs-keyword">extends</span> keyof ApiEndpoints[Path],
        Endpoint <span class="hljs-keyword">extends</span> ApiEndpoints[Path][Method]
    &gt;(
        path: Path,
        body: Endpoint <span class="hljs-keyword">extends</span> { body: <span class="hljs-built_in">any</span> } ? Endpoint[<span class="hljs-string">'body'</span>] : <span class="hljs-built_in">never</span>
    ): <span class="hljs-built_in">Promise</span>&lt;Endpoint <span class="hljs-keyword">extends</span> { response: <span class="hljs-built_in">any</span> } ? Endpoint[<span class="hljs-string">'response'</span>] : <span class="hljs-built_in">never</span>&gt; {
        <span class="hljs-comment">// Implementation</span>
        <span class="hljs-keyword">return</span> {} <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>;
    }
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">const</span> api = <span class="hljs-keyword">new</span> ApiClient();

<span class="hljs-comment">// Type-safe API calls</span>
<span class="hljs-keyword">const</span> users = <span class="hljs-keyword">await</span> api.get(<span class="hljs-string">'/users'</span>, { query: { role: <span class="hljs-string">'admin'</span> } });
<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> api.post(<span class="hljs-string">'/users'</span>, { name: <span class="hljs-string">'John'</span>, age: <span class="hljs-number">30</span>, role: <span class="hljs-string">'user'</span> });
</code></pre>
<h2 id="heading-typescript-types-scared-me-until-i-learned-these-4-rules">Typescript Types Scared Me - Until I Learned These 4 Rules</h2>
<p>When I first encountered TypeScript’s infer and conditional types, I closed the tab and hoped I would never see them again. They looked like dark magic - abstract symbols twisted around angle brackets and seemed designed to make my brain hurt.</p>
<p>Types like <code>T extends (infer U)[] ? U : never</code> or <code>DistributiveConditional&lt;T&gt;</code> made me question my entire career choice. But here’s the thing that changed everything: <strong>there aren’t actually complicated concepts dressed up in scary syntax</strong>.</p>
<p>Once I understood 3 simple mental models, they stopped being scary. In this section, I will walk you through the exact concepts that finally made these types click for me, with real-world examples, not theory.</p>
<h3 id="heading-the-fear-is-real-and-its-not-just-about-you">The fear is real, and it’s not just about you</h3>
<p>Let me be clear: If you have felt intimidated by TypeScript’s advanced types, you are in good company. Even experienced developers struggle with conditional types and the infer keywords when they first encounter them.</p>
<p>I remember staring at the code like this and feeling completely lost.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ReturnType&lt;T&gt; = T <span class="hljs-keyword">extends</span> (...args: <span class="hljs-built_in">any</span>[]) =&gt; infer R ? R : <span class="hljs-built_in">never</span>;
</code></pre>
<p>What the hell was <code>infer R</code> supposed to mean? Why are there all question marks and colons? It looked like someone had thrown punctuation at a keyboard and called it a day.</p>
<p>But here is what I wish someone had told me earlier: these advanced types follow predictable patterns. Once you understand the underlying mental models, you will see them everywhere — and more importantly, you will know how and where to use them.</p>
<h3 id="heading-rule-1-conditional-mirror-control-flow">Rule 1: Conditional Mirror Control Flow</h3>
<p><em>“If you understand if…else, you can understand conditional types.”</em></p>
<p>This was my first breakthrough. Conditional types in TypeScript work exactly like conditional statements in JavaScript, just at the type level instead of the value level.</p>
<p>The basic pattern is simple:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> MyType&lt;T&gt; = T <span class="hljs-keyword">extends</span> SomeCondition ? TrueResult : FalseResult;
</code></pre>
<p>Let’s start with something straightforward:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> IsString&lt;T&gt; = T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">string</span> ? <span class="hljs-literal">true</span> : <span class="hljs-literal">false</span>;

<span class="hljs-keyword">type</span> A = IsString&lt;<span class="hljs-string">'hello'</span>&gt;; <span class="hljs-comment">// true</span>
<span class="hljs-keyword">type</span> B = IsString&lt;<span class="hljs-number">123</span>&gt;;     <span class="hljs-comment">// false</span>
<span class="hljs-keyword">type</span> C = IsString&lt;<span class="hljs-built_in">boolean</span>&gt;; <span class="hljs-comment">// false</span>
</code></pre>
<p>See? It’s just an if statement for types. When the type on the left of <code>extends</code> is assignable to the one on the right, you get the type in the first branch (the "true" branch); otherwise, you get the type in the latter branch (the "false" branch).</p>
<p><strong>Here’s where it gets practical.</strong> Let’s say you’re building a component that should behave differently based on its props:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ButtonProps&lt;T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">boolean</span>&gt; = {
  loading: T;
} &amp; (T <span class="hljs-keyword">extends</span> <span class="hljs-literal">true</span> 
  ? { onClick?: <span class="hljs-built_in">never</span>; disabled: <span class="hljs-literal">true</span> } 
  : { onClick: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span>; disabled?: <span class="hljs-built_in">boolean</span> }
);

<span class="hljs-comment">// When loading is true, onClick is forbidden and disabled is required</span>
<span class="hljs-keyword">const</span> loadingButton: ButtonProps&lt;<span class="hljs-literal">true</span>&gt; = {
  loading: <span class="hljs-literal">true</span>,
  disabled: <span class="hljs-literal">true</span>,
  <span class="hljs-comment">// onClick: () =&gt; {} // ❌ Type error! Can't have onClick when loading</span>
};

<span class="hljs-comment">// When loading is false, onClick is required</span>
<span class="hljs-keyword">const</span> normalButton: ButtonProps&lt;<span class="hljs-literal">false</span>&gt; = {
  loading: <span class="hljs-literal">false</span>,
  onClick: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Clicked!'</span>),
  disabled: <span class="hljs-literal">false</span>
};
</code></pre>
<p><strong>The mental model:</strong> Think of conditional types as TypeScript’s way of saying: “If this type looks like that, then give me this other type, otherwise give me something else“</p>
<h3 id="heading-rule-2-distributive-magic-happens-with-naked-types">Rule 2: Distributive Magic Happens with Naked Types</h3>
<p><em>“When you pass a union, TypeScript loops over each part—unless you stop it.”</em></p>
<p>This one took me way longer to understand, but it’s incredibly powerful once it clicks.</p>
<p>When conditional types act on a generic type, they become distributed when given a union type. That means TypeScript automatically applies the conditional type to each member of the union separately.</p>
<p><strong>Here’s the key:</strong> This only happens with “naked” type parameters.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// This is "naked" - T appears directly in the extends clause</span>
<span class="hljs-keyword">type</span> ToArray&lt;T&gt; = T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">any</span> ? T[] : <span class="hljs-built_in">never</span>;

<span class="hljs-keyword">type</span> Result = ToArray&lt;<span class="hljs-string">'a'</span> | <span class="hljs-string">'b'</span> | <span class="hljs-string">'c'</span>&gt;;
<span class="hljs-comment">// Result is: 'a'[] | 'b'[] | 'c'[]</span>
<span class="hljs-comment">// NOT: ('a' | 'b' | 'c')[]</span>
</code></pre>
<p><strong>Why does this happen?</strong> TypeScript takes the union <code>'a' | 'b' | 'c'</code> and distributes it:</p>
<ul>
<li><p><code>'a' extends any ? 'a'[] : never</code> → <code>'a'[]</code></p>
</li>
<li><p><code>'b' extends any ? 'b'[] : never</code> → <code>'b'[]</code></p>
</li>
<li><p><code>'c' extends any ? 'c'[] : never</code> → <code>'c'[]</code></p>
</li>
</ul>
<p>Then it unites the results: <code>'a'[] | 'b'[] | 'c'[]</code></p>
<p><strong>But here’s how you can turn off this behavior</strong> when you don’t want it:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Wrap T in brackets to make it "non-naked"</span>
<span class="hljs-keyword">type</span> NoDistribute&lt;T&gt; = [T] <span class="hljs-keyword">extends</span> [<span class="hljs-built_in">any</span>] ? T[] : <span class="hljs-built_in">never</span>;

<span class="hljs-keyword">type</span> Result2 = NoDistribute&lt;<span class="hljs-string">'a'</span> | <span class="hljs-string">'b'</span> | <span class="hljs-string">'c'</span>&gt;;
<span class="hljs-comment">// Result2 is: ('a' | 'b' | 'c')[]</span>
</code></pre>
<p><strong>Real example:</strong> Filtering types from a union.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> NonNullable&lt;T&gt; = T <span class="hljs-keyword">extends</span> <span class="hljs-literal">null</span> | <span class="hljs-literal">undefined</span> ? <span class="hljs-built_in">never</span> : T;

<span class="hljs-keyword">type</span> Clean = NonNullable&lt;<span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span> | <span class="hljs-built_in">number</span> | <span class="hljs-literal">undefined</span>&gt;;
<span class="hljs-comment">// Clean is: string | number</span>
<span class="hljs-comment">// The null and undefined get filtered out automatically!</span>
</code></pre>
<p>This distributive property can be used to filter union types, which is exactly how TypeScript’s built-in <code>Exclude</code> utility-type works.</p>
<h3 id="heading-rule-3-infer-lets-you-peek-inside-a-type">Rule 3: Infer lets you peek inside a type</h3>
<p><em>“You can extract types from other types like a pattern matcher.”</em></p>
<p>The infer keyword was the final boss of my TypeScript learning journey. But once I understood it, everything clicked.</p>
<p><strong>Think of</strong> <code>infer</code> <strong>as saying:</strong> "Hey TypeScript, I don’t know what this type is yet, but when you figure it out, store it in this variable so I can use it.”</p>
<p>Conditional types provide us with a way to infer from types we compare against in the true branch using the infer keyword.</p>
<p>Here’s the classic example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ReturnType&lt;T&gt; = T <span class="hljs-keyword">extends</span> (...args: <span class="hljs-built_in">any</span>[]) =&gt; infer R ? R : <span class="hljs-built_in">never</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getName</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span> </span>{ <span class="hljs-keyword">return</span> <span class="hljs-string">"John"</span>; }
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getAge</span>(<span class="hljs-params"></span>): <span class="hljs-title">number</span> </span>{ <span class="hljs-keyword">return</span> <span class="hljs-number">25</span>; }

<span class="hljs-keyword">type</span> NameType = ReturnType&lt;<span class="hljs-keyword">typeof</span> getName&gt;; <span class="hljs-comment">// string</span>
<span class="hljs-keyword">type</span> AgeType = ReturnType&lt;<span class="hljs-keyword">typeof</span> getAge&gt;;   <span class="hljs-comment">// number</span>
</code></pre>
<p><strong>What’s happening here?</strong></p>
<ol>
<li><p>We check if <code>T</code> looks like a function <code>(...args: any[]) =&gt; something</code></p>
</li>
<li><p>If it does, we say “whatever that ‘something’ is, call it <code>R</code>"</p>
</li>
<li><p>Then we return <code>R</code></p>
</li>
<li><p>If it doesn’t look like a function, return <code>never</code></p>
</li>
</ol>
<p><strong>Let’s build something more practical</strong> — extracting array element types:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ArrayElement&lt;T&gt; = T <span class="hljs-keyword">extends</span> (infer U)[] ? U : <span class="hljs-built_in">never</span>;

<span class="hljs-keyword">type</span> StringArray = <span class="hljs-built_in">string</span>[];
<span class="hljs-keyword">type</span> NumberArray = <span class="hljs-built_in">number</span>[];

<span class="hljs-keyword">type</span> StringType = ArrayElement&lt;StringArray&gt;; <span class="hljs-comment">// string</span>
<span class="hljs-keyword">type</span> NumberType = ArrayElement&lt;NumberArray&gt;; <span class="hljs-comment">// number</span>
<span class="hljs-keyword">type</span> NotArray = ArrayElement&lt;<span class="hljs-built_in">boolean</span>&gt;; <span class="hljs-comment">// never</span>
</code></pre>
<p><strong>Here’s where it gets really powerful</strong> — extracting component props:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> PropsOf&lt;T&gt; = T <span class="hljs-keyword">extends</span> React.ComponentType&lt;infer P&gt; ? P : <span class="hljs-built_in">never</span>;

<span class="hljs-keyword">const</span> MyButton: React.FC&lt;{ label: <span class="hljs-built_in">string</span>; onClick: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">void</span> }&gt; = <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> (
  &lt;button onClick={props.onClick}&gt;{props.label}&lt;/button&gt;
);

<span class="hljs-keyword">type</span> MyButtonProps = PropsOf&lt;<span class="hljs-keyword">typeof</span> MyButton&gt;;
<span class="hljs-comment">// MyButtonProps is: { label: string; onClick: () =&gt; void }</span>
</code></pre>
<p><strong>Multiple infer declarations</strong> work too:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> FunctionInfo&lt;T&gt; = T <span class="hljs-keyword">extends</span> (first: infer A, second: infer B) =&gt; infer R 
  ? { args: [A, B]; <span class="hljs-keyword">return</span>: R } 
  : <span class="hljs-built_in">never</span>;

<span class="hljs-keyword">type</span> LoginFunction = <span class="hljs-function">(<span class="hljs-params">username: <span class="hljs-built_in">string</span>, password: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">boolean</span>&gt;;

<span class="hljs-keyword">type</span> LoginInfo = FunctionInfo&lt;LoginFunction&gt;;
<span class="hljs-comment">// LoginInfo is: { args: [string, string]; return: Promise&lt;boolean&gt; }</span>
</code></pre>
<h3 id="heading-rule-4-map-types-arent-hard-if-you-start-smart">Rule 4: Map Types Aren’t Hard if You Start Smart</h3>
<p>Now that you understand conditional types and infer, mapped types will feel like a breeze.</p>
<p><strong>Mapped types transform existing types.</strong> Think of them as a <code>for...in</code> loop for type properties.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Optional&lt;T&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T]?: T[K];
}
</code></pre>
<p><strong>In plain English:</strong> “For each property <code>K</code> in type <code>T</code>, make a new property with the same name but optional, and the same type <code>T[K]</code>."</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> User = {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
};

<span class="hljs-keyword">type</span> PartialUser = Optional&lt;User&gt;;
<span class="hljs-comment">// PartialUser is: {</span>
<span class="hljs-comment">//   id?: number;</span>
<span class="hljs-comment">//   name?: string;</span>
<span class="hljs-comment">//   email?: string;</span>
<span class="hljs-comment">// }</span>
</code></pre>
<p><strong>Let’s build something more interesting</strong> — converting all properties to strings:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Stringify&lt;T&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T]: <span class="hljs-built_in">string</span>;
}


<span class="hljs-keyword">type</span> StringifiedUser = Stringify&lt;User&gt;;
<span class="hljs-comment">// StringifiedUser is: {</span>
<span class="hljs-comment">//   id: string;</span>
<span class="hljs-comment">//   name: string;</span>
<span class="hljs-comment">//   email: string;</span>
<span class="hljs-comment">// }</span>
</code></pre>
<p><strong>Combining mapped types with conditional types:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> NonFunctionPropertyNames&lt;T&gt; = {
  [K <span class="hljs-keyword">in</span> keyof T]: T[K] <span class="hljs-keyword">extends</span> <span class="hljs-built_in">Function</span> ? <span class="hljs-built_in">never</span> : K;
}[keyof T];

<span class="hljs-keyword">type</span> NonFunctionProperties&lt;T&gt; = Pick&lt;T, NonFunctionPropertyNames&lt;T&gt;&gt;;

<span class="hljs-keyword">class</span> UserService {
  id: <span class="hljs-built_in">number</span> = <span class="hljs-number">1</span>;
  name: <span class="hljs-built_in">string</span> = <span class="hljs-string">"John"</span>;
  save(): <span class="hljs-built_in">void</span> {}
  <span class="hljs-keyword">delete</span>(): <span class="hljs-built_in">void</span> {}
}

<span class="hljs-keyword">type</span> UserData = NonFunctionProperties&lt;UserService&gt;;
<span class="hljs-comment">// UserData is: { id: number; name: string }</span>
<span class="hljs-comment">// Methods are filtered out!</span>
</code></pre>
<h3 id="heading-putting-it-all-together-a-real-world-example">Putting it all together: A Real-World Example</h3>
<p>Let’s build a type that extracts the payload type from Redux actions:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Our action types</span>
<span class="hljs-keyword">type</span> LoginAction = { <span class="hljs-keyword">type</span>: <span class="hljs-string">'LOGIN'</span>; payload: { username: <span class="hljs-built_in">string</span>; password: <span class="hljs-built_in">string</span> } };
<span class="hljs-keyword">type</span> LogoutAction = { <span class="hljs-keyword">type</span>: <span class="hljs-string">'LOGOUT'</span>; payload: <span class="hljs-literal">null</span> };
<span class="hljs-keyword">type</span> UpdateProfileAction = { <span class="hljs-keyword">type</span>: <span class="hljs-string">'UPDATE_PROFILE'</span>; payload: { name: <span class="hljs-built_in">string</span>; email: <span class="hljs-built_in">string</span> } };

<span class="hljs-keyword">type</span> Actions = LoginAction | LogoutAction | UpdateProfileAction;

<span class="hljs-comment">// Extract payload type for a specific action</span>
<span class="hljs-keyword">type</span> PayloadOf&lt;T, ActionType <span class="hljs-keyword">extends</span> <span class="hljs-built_in">string</span>&gt; = T <span class="hljs-keyword">extends</span> { <span class="hljs-keyword">type</span>: ActionType; payload: infer P } 
  ? P 
  : <span class="hljs-built_in">never</span>;

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">type</span> LoginPayload = PayloadOf&lt;Actions, <span class="hljs-string">'LOGIN'</span>&gt;;
<span class="hljs-comment">// LoginPayload is: { username: string; password: string }</span>

<span class="hljs-keyword">type</span> LogoutPayload = PayloadOf&lt;Actions, <span class="hljs-string">'LOGOUT'</span>&gt;;
<span class="hljs-comment">// LogoutPayload is: null</span>

<span class="hljs-keyword">type</span> UpdatePayload = PayloadOf&lt;Actions, <span class="hljs-string">'UPDATE_PROFILE'</span>&gt;;
<span class="hljs-comment">// UpdatePayload is: { name: string; email: string }</span>
</code></pre>
<p><strong>What’s happening:</strong></p>
<ol>
<li><p>We use distributive conditional types to check each action in the union</p>
</li>
<li><p>We use <code>infer</code> to extract the payload type when the action type matches</p>
</li>
<li><p>TypeScript gives us exactly the payload type we need!</p>
</li>
</ol>
<p>Now that you understand these three rules, you’ll start seeing patterns everywhere in TypeScript’s built-in utility types:</p>
<ul>
<li><p><code>Pick&lt;T, K&gt;</code> uses mapped types</p>
</li>
<li><p><code>Exclude&lt;T, U&gt;</code> uses distributive conditional types</p>
</li>
<li><p><code>ReturnType&lt;T&gt;</code> uses <code>infer</code></p>
</li>
<li><p><code>Parameters&lt;T&gt;</code> combining conditional types with <code>infer</code></p>
</li>
</ul>
<h2 id="heading-clean-react-with-typescript">Clean React With TypeScript</h2>
<p>Today, I use TypeScript on a daily basis and actually like it quite a bit, even though I regularly break the compiler. One thing that took me quite some time, though, was figuring out the best way to add TypeScript to all the React patterns and features. I have seen it done in so many ways, ending up confused by all the different types in the library itself.</p>
<p>To help you avoid that struggle or/and to improve your existing codebase, this article explores different use cases and - in my opinion - most elegant solutions.</p>
<h3 id="heading-components">Components</h3>
<p>First of all, let’s talk about components.</p>
<p>They are the heart of every React application and probably the thing you write the most often. Even since the introduction of hooks, most components are plain JavaScript functions that take a set of props and return some markup, usually in the form of JSX.</p>
<p>Given that, typing them is definitely straightforward. The only real constraint is that it always takes a single argument - an object of properties, to be precise.</p>
<ol>
<li><strong>Basic Props</strong></li>
</ol>
<p>Let’s start with some primitive props first. In this example, we have a component that takes a title and a description. Both are strings, and description is optional.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Props = {
  title: <span class="hljs-built_in">string</span>
  description?: <span class="hljs-built_in">string</span>
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductTile</span>(<span class="hljs-params">{ title, description }: Props</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;div&gt;{title}&lt;/div&gt;
      {description &amp;&amp; &lt;div&gt;{description&lt;/div&gt;}
    &lt;/div&gt;
  )
}
</code></pre>
<ol start="2">
<li><strong>Children</strong></li>
</ol>
<p>So far, so good. Now, a common use case is to pass children to a component in order to render nested components. You might be inclined to add it to your type, but React actually provides a special type that could help you reduce redundancy.</p>
<p>It’s called <code>PropsWithChildren</code> and it’s a generic type that takes your existing props type and adds the <code>children</code> for you.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ReactNode, PropsWithChildren } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">type</span> Props = {
  title: <span class="hljs-built_in">string</span>
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductTile</span>(<span class="hljs-params">{ title, children }: PropsWithChildren&lt;Props&gt;</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;div&gt;{title}&lt;/div&gt;
      {children}
    &lt;/div&gt;
  )
}
</code></pre>
<p>Tip: This argument is optional. If your component only takes children, you can pass <code>PropsWithChildren</code> on its own.</p>
<ol start="3">
<li><strong>Piping Props</strong></li>
</ol>
<p>Another common thing to do is piping props into inner components. For example, you might have a component that itself renders our <code>ProductTile</code> component, but also accepts additional props for customization.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> ProductTile <span class="hljs-keyword">from</span> <span class="hljs-string">'./ProductTile'</span>

<span class="hljs-keyword">type</span> Props = {
  color: <span class="hljs-built_in">string</span>
  title: <span class="hljs-built_in">string</span>
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProminentProductTile</span>(<span class="hljs-params">{ color, title }: Props</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div style={{ background: color }}&gt;
      &lt;ProductTile title={title} /&gt;
    &lt;/div&gt;
  )
}
</code></pre>
<p>While this is totally fine for primitive types such as strings or numbers, it can become cumbersome to repeat those types if you are dealing with complex records or functions, especially if you have to pass a value through multiple components.</p>
<p>Remember the DRY rule? Instead of repeating the same types over and over, we can leverage another generic provided by React, which is <code>ComponentProps</code>. It takes the type of a component that we can get by <code>typeof</code> and returns its props type. We can then use indexed access to get the specific value.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ComponentProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">import</span> ProductTile <span class="hljs-keyword">from</span> <span class="hljs-string">'./ProductTile'</span>

<span class="hljs-keyword">type</span> ProductTileProps = ComponentProps&lt;<span class="hljs-keyword">typeof</span> ProductTile&gt;
<span class="hljs-keyword">type</span> Props = {
  color: <span class="hljs-built_in">string</span>
  title: ProductTileProps[<span class="hljs-string">'title'</span>]
}
</code></pre>
<p>You can argue that we can achieve the same by simply exporting the type from ProductTile. And you are right, that works too, but it’s also more prone to errors if you change your types and/or extend them at some point.</p>
<ol start="4">
<li><strong>Spreading Props</strong></li>
</ol>
<p>Similar to piping props, sometimes we want to spread all extra props to some underlying component. Imagine the <code>ProminentProductTile</code> should pipe both <code>title</code> and <code>description</code>.</p>
<p>Instead of specifying each property one by one, we can simply extend the type we can leveraging <code>ComponentProps</code> once again.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ComponentProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">import</span> ProductTile <span class="hljs-keyword">from</span> <span class="hljs-string">'./ProductTile'</span>

<span class="hljs-keyword">type</span> Props = {
  color: <span class="hljs-built_in">string</span>
} &amp; ComponentProps&lt;<span class="hljs-keyword">typeof</span> ProductTile&gt;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProminentProductTile</span>(<span class="hljs-params">{ color, ...props }: Props</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div style={{ background: color }}&gt;
      &lt;ProductTile {...props} /&gt;
    &lt;/div&gt;
  )
}
</code></pre>
<p>Tip: If you only want to spread a subset of those types, you can use a Typescript built-in <code>Pick</code> to do so. For example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ProductTileProps = ComponentProps&lt;<span class="hljs-keyword">typeof</span> ProductTile&gt;

<span class="hljs-keyword">type</span> Props = {
  color: <span class="hljs-built_in">string</span>
} &amp; Pick&lt;ProductTileProps, <span class="hljs-string">'title'</span> | <span class="hljs-string">'description'</span>&gt;
</code></pre>
<p><strong>HTML elements</strong></p>
<p>The same pattern also applies to HTML primitives. If you want to pass down all remaining props to e.g, button, we can simply use <code>ComponentProps&lt;“button“&gt;</code>.</p>
<p>Note: There's also <code>React.JSX.IntrinsicElements["button"]</code> which refers to the identical type, but I would recommend you use only one for consistency and readability, and I generally prefer the first as it’s easier to use.</p>
<p>Extra: For certain edge cases where we only want to pass down valid HTML attributes - excluding React-specific props such as ref and key - we can also use specific attribute types, e.g. <code>React.ButtonHTMLAttributes&lt;HTMLButtonElement&gt;</code>. However, I have not yet encountered a use case for those, as it’s once again more to type, I still prefer the shorter <code>ComponentProps&lt;“button“&gt;</code>.</p>
<p><strong>Passing JSX</strong></p>
<p>Now that we have covered simple props, let’s look at some advanced use cases. Sometimes, passing primitive props is not enough, and we want to pass down the raw JSX to render nested content. While dependency injection generally makes your component less predictable, it’s a great way to customize generic components. This is especially useful when we are already passing children, but need to inject additional makeup at a specific position.</p>
<p>Luckily, React provides us a another useful type called <code>ReactNode</code>. Imagine a layout component that wraps your whole application and also receives the sidebar to render a dedicated navigation in a predefined slot.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { PropsWithChildren, ReactNode } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">type</span> Props = {
  title: <span class="hljs-built_in">string</span>
  sidebar: ReactNode
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Layout</span>(<span class="hljs-params">{ title, children, sidebar }: PropsWithChildren&lt;Props&gt;</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      &lt;div className=<span class="hljs-string">"sidebar"</span>&gt;{sidebar}&lt;/div&gt;
      &lt;main className=<span class="hljs-string">"content"</span>&gt;
        &lt;h1&gt;{title}&lt;/h1&gt;
        {children}
      &lt;/main&gt;
    &lt;/&gt;
  )
}
<span class="hljs-comment">// Now we can pass whatever we want</span>
<span class="hljs-keyword">const</span> sidebar = (
  &lt;div&gt;
    &lt;a data-selected href=<span class="hljs-string">"/shoes"</span>&gt;
      Shoes
    &lt;/a&gt;
    &lt;a href=<span class="hljs-string">"/watches"</span>&gt;Watches&lt;/a&gt;
    &lt;a href=<span class="hljs-string">"/shirts"</span>&gt;Shirts&lt;/a&gt;
  &lt;/div&gt;
)

<span class="hljs-keyword">const</span> App = (
  &lt;Layout title=<span class="hljs-string">"Running shoes"</span> sidebar={sidebar}&gt;
    {<span class="hljs-comment">/* Page content */</span>}
  &lt;/Layout&gt;
)
</code></pre>
<p>Bonus: <code>PropsWithChildren</code> is actually using <code>ReactNode</code> under the hood. A custom implementation would look something like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> PropsWithChildren&lt;Props = {}&gt; = { children: ReactNode } &amp; Props
</code></pre>
<p><strong>Passing Components</strong></p>
<p>Passing JSX is great when you want maximum flexibility. But what if you want to restrict rendering to certain components or pass some props to that subtree as well, without moving all the logic into a single component,t bloating it even more?</p>
<p>What became popular as the <a target="_blank" href="https://react.dev/reference/react/Children#calling-a-render-prop-to-customize-rendering">render-prop pattern(new tab) is exactly that: dependen</a>cy injection with constraints.<br />Once again, React has a neat type to help us with that called <code>ComponentType</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ComponentType } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">type</span> ProductTileProps = {
  title: <span class="hljs-built_in">string</span>
  description?: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">type</span> Props = {
  render: ComponentType&lt;ProductTileProps&gt;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductTile</span>(<span class="hljs-params">{ render }: Props</span>) </span>{
  <span class="hljs-comment">// some logic to compute props</span>

  <span class="hljs-keyword">return</span> render(props)
}
</code></pre>
<p><strong>Extra</strong>: This is also quite nice for third-party components via d.ts files:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">module</span> 'some-lib' {
  <span class="hljs-keyword">type</span> Props = {
    title: <span class="hljs-built_in">string</span>
    description?: <span class="hljs-built_in">string</span>
  }

  <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ProductTile: ComponentType&lt;Props&gt;
}
</code></pre>
<p><strong>Specific Components</strong></p>
<p>If we only allow a specific component, the code is even simpler as we can use the built-in <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/typeof-types.html"><code>typeof</code> operator(new tab)</a> to do so.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ComponentProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">import</span> Icon <span class="hljs-keyword">from</span> <span class="hljs-string">'./Icon'</span>

<span class="hljs-keyword">type</span> Props = {
  icon?: <span class="hljs-keyword">typeof</span> Icon
} &amp; ComponentProps&lt;<span class="hljs-string">'button'</span>&gt;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{ icon: Icon, children, ...props }: Props</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;button {...props}&gt;
      {icon &amp;&amp; &lt;Icon size={<span class="hljs-number">24</span>} /&gt;}
      {children}
    &lt;/button&gt;
  )
}
</code></pre>
<p><strong>Inferring Props</strong></p>
<p>This is a common pattern used for generic (layout) components. It's often used in component libraries and can be a great foundation for creating flexible layouts in React.</p>
<p>Usually, you pass an <code>as</code> or <code>component</code> prop and the component becomes that, including its props and types. For example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> App = (
  &lt;&gt;
    {<span class="hljs-comment">/* this throws as div doesn't have a value prop */</span>}
    &lt;Box <span class="hljs-keyword">as</span>=<span class="hljs-string">"div"</span> value=<span class="hljs-string">"foo"</span> /&gt;
    {<span class="hljs-comment">/* this works however */</span>}
    &lt;Box <span class="hljs-keyword">as</span>=<span class="hljs-string">"input"</span> value=<span class="hljs-string">"foo"</span> /&gt;
  &lt;/&gt;
)
</code></pre>
<p>The best part is that it also works with custom components, giving us endless flexibility.<br />Alright, but how do we achieve this? Instead of explaining what <a target="_blank" href="https://www.mattpocock.com/">Matt Pocock(new tab) from Total T</a><a target="_blank" href="https://www.totaltypescript.com/">ypeScript(new tab) already did with</a> a great article, I'm just going to link it here: <a target="_blank" href="https://www.totaltypescript.com/pass-component-as-prop-react#passing-any-component-as-a-prop-and-inferring-its-props">Passing Any Component as a Prop and Inferring Its Props(new tab).</a></p>
<h3 id="heading-state-management">State Management</h3>
<p>Managing state is probably the most common use case for hooks, and React provides both useState for simple cases as well as the useReducer hook for more complex scenarios.</p>
<ol>
<li><strong>useState</strong></li>
</ol>
<p>By default, useState automatically infers the type of the value based on the initial value that is passed. That means, if we have a simple counter state with 0 as the default state, we don’t have to type anything, and it just works:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [counter, setCounter] = useState(<span class="hljs-number">0</span>)

  <span class="hljs-comment">// component logic</span>
}
</code></pre>
<p>However, if we don’t pass a default value, work with nullable values, or the default value doesn’t represent the full type,e.g., when using objects with optional keys, we have to provide a type for it to work properly.</p>
<p>Luckily, React allows us to pass an optional type to tell it what values to accept.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">type</span> AuthState = {
  authenticated: <span class="hljs-built_in">boolean</span>
  user?: {
    firstname: <span class="hljs-built_in">string</span>
    lastname: <span class="hljs-built_in">string</span>
  }
}

<span class="hljs-keyword">type</span> Todo = {
  id: <span class="hljs-built_in">string</span>
  title: <span class="hljs-built_in">string</span>
  completed: <span class="hljs-built_in">boolean</span>
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// without passing AuthState, we wouldn't be able to set the user</span>
  <span class="hljs-keyword">const</span> [authState, setAuthState] = useState&lt;AuthState&gt;({
    authenticated: <span class="hljs-literal">false</span>,
  })
  <span class="hljs-comment">// data is loaded asynchronously and thus null on first render</span>
  <span class="hljs-keyword">const</span> [data, setData] = useState&lt;<span class="hljs-built_in">Array</span>&lt;Todo&gt; | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>)

  <span class="hljs-comment">// component logic</span>
}
</code></pre>
<ol start="2">
<li><strong>useReducer</strong></li>
</ol>
<p>When working with reducers, there is no type inference because we have to actively type the reducer anyway. Its first argument (state) will be used to infer the type and also to type-check the initial state that is being passed to the hook.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useReducer } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">type</span> State = <span class="hljs-built_in">number</span>
<span class="hljs-keyword">type</span> Action =
  | { <span class="hljs-keyword">type</span>: <span class="hljs-string">'increment'</span> }
  | { <span class="hljs-keyword">type</span>: <span class="hljs-string">'decrement'</span> }
  | { <span class="hljs-keyword">type</span>: <span class="hljs-string">'reset'</span>; payload: <span class="hljs-built_in">number</span> }

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reducer</span>(<span class="hljs-params">state: State, action: Action</span>) </span>{
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'increment'</span>:
      <span class="hljs-keyword">return</span> state + <span class="hljs-number">1</span>
    <span class="hljs-keyword">case</span> <span class="hljs-string">'decrement'</span>:
      <span class="hljs-keyword">return</span> state - <span class="hljs-number">1</span>
    <span class="hljs-keyword">case</span> <span class="hljs-string">'reset'</span>:
      <span class="hljs-keyword">return</span> action.payload
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [state, dispatch] = useReducer(reducer, <span class="hljs-number">0</span>)

  <span class="hljs-comment">// component logic</span>
}
</code></pre>
<p>After all, it's all just pure TypeScript and no React specifics here.</p>
<h3 id="heading-refs">Refs</h3>
<p>Refs, short for reference, provide a way to directly access and interacts with the DOM elements or React components.</p>
<p>While I would recommend you only use refs when necessary and rely on components and states whenever possible, they can be quite useful for focus management or reading/manipulating a node directly.</p>
<blockquote>
<p>Note: Ref can be used for all kind of things and values, but we will focus only on HTML elements</p>
</blockquote>
<ol>
<li><strong>Using Refs</strong></li>
</ol>
<p>React provides a convenient hook <code>useRef</code> that creates a ref inside a functional component.</p>
<p>In order to get proper types and no compiler errors, we have to provide a type. Since the element is not yet mounted on first render, we also pass null as a default.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useRef, ComponentProps } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">props: ComponentProps&lt;'button'&gt;</span>) </span>{
  <span class="hljs-keyword">const</span> ref = useRef&lt;HTMLButtonElement&gt;(<span class="hljs-literal">null</span>)

  <span class="hljs-keyword">return</span> &lt;button ref={ref} {...props} /&gt;
}
</code></pre>
<ol start="2">
<li><strong>Forwarding Refs</strong></li>
</ol>
<blockquote>
<p>Note: Forwarding refs will soon be a thing of the past. Once React 19 hits, refs will be forwarded automatically, with no need to wrap components in forwardRef anymore.</p>
</blockquote>
<p><a target="_blank" href="https://react.dev/reference/react/forwardRef">Forwarding refs</a> is necessary when we want to pass a ref into a custom component. Let’s take the button with the icon from above. Something I have seen a lot in code bases is typing the props and the ref individually.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { forwardRef, ComponentProps, ForwardedRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">import</span> Icon <span class="hljs-keyword">from</span> <span class="hljs-string">'./Icon'</span>

<span class="hljs-keyword">type</span> Props = {
  icon?: <span class="hljs-keyword">typeof</span> Icon
} &amp; ComponentProps&lt;<span class="hljs-string">'button'</span>&gt;

<span class="hljs-keyword">const</span> Button = forwardRef(
  <span class="hljs-function">(<span class="hljs-params">
    { icon, children, ...props }: Props,
    ref: ForwardedRef&lt;HTMLButtonElement&gt;
  </span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
      &lt;button ref={ref} {...props}&gt;
        {icon &amp;&amp; &lt;Icon size={<span class="hljs-number">24</span>} /&gt;}
        {children}
      &lt;/button&gt;
    )
  }
)
</code></pre>
<p>I always find this code quite hard to read as there's a lot going on with many parenthesis and brackets. But, it doesn't have to be that way! forwardRef accepts two optional types to initialise it's function button:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Button = forwardRef&lt;HTMLButtonElement, Props&gt;(
  <span class="hljs-function">(<span class="hljs-params">{ icon, children, ...props }, ref</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> (
      &lt;button ref={ref} {...props}&gt;
        {icon &amp;&amp; &lt;Icon size={<span class="hljs-number">24</span>} /&gt;}
        {children}
      &lt;/button&gt;
    )
  }
)
</code></pre>
<p>This results not only in more readable code, but also reduces some of the boilerplate, as we don't need <code>ForwardedRef</code> at all.</p>
<ol start="3">
<li><strong>Passing Refs</strong></li>
</ol>
<p>Sometimes, we don't want to forward a ref directly, but rather pass a ref to another element. Imagine you have a popover component and want to pass which element it should anchor to. We can do that by passing a ref. To do so, React provides a <code>RefObject</code> type.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { RefObject } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">type</span> Props = {
  anchor: RefObject&lt;HTMLElement&gt;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Popover</span>(<span class="hljs-params">{ anchor }: Props</span>) </span>{
  <span class="hljs-comment">// position component according to the anchor ref</span>
}
</code></pre>
<p><strong>Tip</strong>: Generally speaking, I recommend using more universal types such as <code>HTMLElement</code> unless you need specific attributes or want to limit the API, e.g., when building a component library. Why? Because <code>HTMLDivElement</code> also satisfies <code>HTMLElement</code>, but <code>HTMLSpanElement</code> doesn't satisfy <code>HTMLDivElement</code>.</p>
<h3 id="heading-events">Events</h3>
<p>Last but not least, let’s talk about events and event listeners</p>
<p>We usually encounter them in two ways:</p>
<ul>
<li><p>Passing event listeners to components directly via props, e.g. <code>onClick</code>, <code>onBlur</code></p>
</li>
<li><p>Adding event listeners in effects when targeting different elements, e.g. <code>scroll</code> <code>mouseup</code></p>
</li>
</ul>
<p>However, before we dive into both use cases, we should first talk about the different event types, where they come from, and what the differences are.</p>
<ol>
<li><strong>MouseEvent vs. React.mouseEvent</strong></li>
</ol>
<p>At the beginning, this really confused me. There's both a global <code>MouseEvent</code> as well as <code>MouseEvent</code> exported by React. They are both used for event listeners, and I have seen them mixed up more than once.</p>
<p>To put it simply, the difference is that the global built-in <code>MouseEvent</code> refers to native JavaScript events, while the other one is specifically tailored for React's <a target="_blank" href="https://react.dev/reference/react-dom/components/common#react-event-object">Synthetic Event System</a>.</p>
<p>They have a lot in common and can often be used interchangeably, but the React version also accounts for browser incompatibilities and includes some React-specific properties such as <code>persist</code>.</p>
<p>Besides mouse events, there are all sorts of events for every kind of event listener.</p>
<p><strong>Note</strong>: In older versions prior to React 17, synthetic events would also be pooled, which means that the event object is reused for performance reasons.</p>
<ol start="2">
<li><strong>Passing Event Listeners</strong></li>
</ol>
<p>The first use case is passing event listeners to components. When doing so, we're using React's own event system and thus should use the special events provided by React.</p>
<p>The most common example is passing a <code>onClick</code> handler to a clickable component.</p>
<p><strong>Note</strong>: Once again, we should most likely be using <code>ComponentProps&lt;"button"&gt;["onClick"]</code> here, but just for the sake of exploring the types, we will write the type ourselves.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { MouseEventHandler } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">type</span> Props = {
  onClick: MouseEventHandler&lt;HTMLButtonElement&gt;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{ onClick }: Props</span>) </span>{
  <span class="hljs-keyword">return</span> &lt;button onClick={onClick} /&gt;
}
</code></pre>
<p>Another common thing is to manipulate event listeners, e.g., when submitting a form. In that case, we have to type the event to get the proper type.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// using named imports would overwrite the native events here</span>
<span class="hljs-comment">// it's more safe to do it this way, in case we want to use both in a single file</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Login</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;form
      onSubmit={<span class="hljs-function">(<span class="hljs-params">e: React.FormEvent&lt;HTMLFormElement&gt;</span>) =&gt;</span> {
        e.preventDefault()

        <span class="hljs-comment">// login logic</span>
      }}&gt;
      {<span class="hljs-comment">/* Login form */</span>}
    &lt;/form&gt;
  )
}
</code></pre>
<ol start="3">
<li><strong>Attaching Event Listeners</strong></li>
</ol>
<p>Finally, the last thing to discuss is attaching event listeners. This is primarily useful when dealing with events that can't be passed to the component directly such as a global scroll listener.</p>
<p>Typically, we register the event listener in a <code>useEffect</code>.<br />Since those are native event listeners and have nothing to do with React, we get the native events and should use the native types as well.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Navigation</span>(<span class="hljs-params"></span>) </span>{
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> onScroll = <span class="hljs-function">(<span class="hljs-params">e: Event</span>) =&gt;</span> {
      <span class="hljs-comment">// do something when scrolling</span>
    }

    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">'scroll'</span>, onScroll)
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">document</span>.removeEventListener(<span class="hljs-string">'scroll'</span>, onScroll)
  }, [])

  <span class="hljs-comment">// component logic</span>
}
</code></pre>
<h2 id="heading-react-typescript-best-practices">React TypeScript Best Practices</h2>
<h3 id="heading-using-as-const-for-literal-type-inference">Using <code>as const</code> for Literal Type Inference</h3>
<p>When defining static values like status codes, roles, or feature flags, <code>as const</code> helps infer <strong>literal values</strong> instead of general types.</p>
<p><strong>❌ Without</strong> <code>as const</code><strong>:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> roles = [<span class="hljs-string">"admin"</span>, <span class="hljs-string">"user"</span>, <span class="hljs-string">"moderator"</span>];
<span class="hljs-keyword">type</span> Role = <span class="hljs-keyword">typeof</span> roles[<span class="hljs-built_in">number</span>]; <span class="hljs-comment">// string</span>
</code></pre>
<p><strong>✅ With</strong> <code>as const</code><strong>:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> roles = [<span class="hljs-string">"admin"</span>, <span class="hljs-string">"user"</span>, <span class="hljs-string">"moderator"</span>] <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;
<span class="hljs-keyword">type</span> Role = <span class="hljs-keyword">typeof</span> roles[<span class="hljs-built_in">number</span>]; <span class="hljs-comment">// "admin" | "user" | "moderator"</span>
</code></pre>
<p>Use this for dropdowns, tabs, or enum-like values to get strong type safety and autocomplete.</p>
<h3 id="heading-discriminated-unions-for-conditional-component-logic">Discriminated Unions for Conditional Component Logic</h3>
<p>Discriminated (tagged) unions let you safely switch between component variations without manual type checks.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Field =
  | { <span class="hljs-keyword">type</span>: <span class="hljs-string">"text"</span>; label: <span class="hljs-built_in">string</span> }
  | { <span class="hljs-keyword">type</span>: <span class="hljs-string">"checkbox"</span>; checked: <span class="hljs-built_in">boolean</span> };

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RenderField</span>(<span class="hljs-params">field: Field</span>) </span>{
  <span class="hljs-keyword">if</span> (field.type === <span class="hljs-string">"text"</span>) <span class="hljs-keyword">return</span> &lt;input placeholder={field.label} /&gt;;
  <span class="hljs-keyword">if</span> (field.type === <span class="hljs-string">"checkbox"</span>) <span class="hljs-keyword">return</span> &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"checkbox"</span> checked={field.checked} /&gt;;
}
</code></pre>
<p>🔍 TypeScript narrows the type based on <code>field.type</code>, so you get complete inference in each branch. No type casting, no fuss.</p>
<h3 id="heading-generics-in-custom-hooks">Generics in Custom Hooks</h3>
<p>Want reusable data-fetching hooks? Generics are the key:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useFetch</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">url: <span class="hljs-built_in">string</span></span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState&lt;T | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);
  <span class="hljs-comment">// fetch logic...</span>
  <span class="hljs-keyword">return</span> { data };
}
</code></pre>
<p>Usage:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> User = { id: <span class="hljs-built_in">number</span>; name: <span class="hljs-built_in">string</span> };
<span class="hljs-keyword">const</span> { data } = useFetch&lt;User&gt;(<span class="hljs-string">"/api/user"</span>);
</code></pre>
<p>Your data is fully typed — no need to cast or guess field names.</p>
<h3 id="heading-utility-types-for-cleaner-props">Utility Types for Cleaner Props</h3>
<p>Use <code>Partial</code>, <code>Pick</code>, <code>Omit</code>, <code>Record</code>, etc., to build more flexible components:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> InputProps = Pick&lt;React.InputHTMLAttributes&lt;HTMLInputElement&gt;, <span class="hljs-string">"type"</span> | <span class="hljs-string">"value"</span>&gt;;

<span class="hljs-keyword">const</span> Input = <span class="hljs-function">(<span class="hljs-params">props: InputProps</span>) =&gt;</span> &lt;input {...props} /&gt;;
</code></pre>
<p><strong>Common patterns:</strong></p>
<ul>
<li><p><code>Omit&lt;T, "prop"&gt;</code> — Remove a specific prop</p>
</li>
<li><p><code>Partial&lt;T&gt;</code> — Make all fields optional</p>
</li>
<li><p><code>Record&lt;K, V&gt;</code> — Map keys to values</p>
</li>
</ul>
<p>These reduce boilerplate while increasing maintainability.</p>
<h3 id="heading-infer-props-from-zod-or-api-contracts">Infer Props from Zod or API Contracts</h3>
<p>Instead of duplicating types, infer them directly from validation schemas:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> userSchema = z.object({
  name: z.string(),
  email: z.string().email(),
});

<span class="hljs-keyword">type</span> User = z.infer&lt;<span class="hljs-keyword">typeof</span> userSchema&gt;;
</code></pre>
<p>Use <code>User</code> for API requests, forms, and even Redux or Zustand states. One source of truth. Zero inconsistencies.</p>
<h3 id="heading-overloading-props-in-polymorphic-components">Overloading Props in Polymorphic Components</h3>
<p>Polymorphic components like buttons that render as <code>&lt;a&gt;</code> or <code>&lt;button&gt;</code> require flexible typing:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> ButtonProps =
  | ({ <span class="hljs-keyword">as</span>?: <span class="hljs-string">"button"</span> } &amp; React.ButtonHTMLAttributes&lt;HTMLButtonElement&gt;)
  | ({ <span class="hljs-keyword">as</span>: <span class="hljs-string">"a"</span> } &amp; React.AnchorHTMLAttributes&lt;HTMLAnchorElement&gt;);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{ <span class="hljs-keyword">as</span> = "button", ...rest }: ButtonProps</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">as</span> === <span class="hljs-string">"a"</span>) <span class="hljs-keyword">return</span> &lt;a {...rest} /&gt;;
  <span class="hljs-keyword">return</span> &lt;button {...rest} /&gt;;
}
</code></pre>
<p>🔁 Clean API for users. Full type safety for you.</p>
<h3 id="heading-advanced-keyof-and-in-for-dynamic-uis">Advanced <code>keyof</code> and <code>in</code> for Dynamic UIs</h3>
<p>For forms, tables, or editors that need to render based on object keys:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> User = { id: <span class="hljs-built_in">number</span>; name: <span class="hljs-built_in">string</span>; email: <span class="hljs-built_in">string</span> };

<span class="hljs-keyword">type</span> UserKeys = keyof User; <span class="hljs-comment">// "id" | "name" | "email"</span>

<span class="hljs-keyword">const</span> headers: Record&lt;UserKeys, <span class="hljs-built_in">string</span>&gt; = {
  id: <span class="hljs-string">"ID"</span>,
  name: <span class="hljs-string">"Name"</span>,
  email: <span class="hljs-string">"Email Address"</span>,
};
</code></pre>
<p><strong>Use these patterns in:</strong></p>
<ul>
<li><p>Form builders (<code>fields: Array&lt;keyof Schema&gt;</code>)</p>
</li>
<li><p>Table components (<code>columns.map(col =&gt; row[col])</code>)</p>
</li>
<li><p>Dynamic accessors (<code>object[key as keyof typeof object]</code>)</p>
</li>
</ul>
<h3 id="heading-satisfies-for-constrained-literals"><code>satisfies</code> for Constrained Literals</h3>
<p>Keep type inference but enforce constraints. Perfect for config objects:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> config = {
  theme: <span class="hljs-string">"dark"</span>,
  layout: <span class="hljs-string">"grid"</span>,
} satisfies Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt;;
</code></pre>
<p>Unlike full typing, <code>satisfies</code> doesn’t lose literal values. Great for avoiding casting or inference loss.</p>
<h3 id="heading-should-you-use-reactfc">Should you use <code>React.FC</code>?</h3>
<p>Short answer: probably not — but there’s nuance.</p>
<p>Want a deep dive? Read <a target="_blank" href="https://medium.com/web-tech-journals/react-fc-in-typescript-should-you-use-react-functional-components-af4295d87d80?sk=5cf8cd13186993f6cbcd55c8e67c9b15">the full article</a>.</p>
<p><strong>✅ Pros:</strong></p>
<ul>
<li><p>Automatically types <code>children</code></p>
</li>
<li><p>Slightly shorter syntax for quick scaffolding</p>
</li>
</ul>
<p><strong>❌ Cons:</strong></p>
<ul>
<li><p>Forces <code>children</code> even when not needed</p>
</li>
<li><p>Hides the component’s actual prop type</p>
</li>
<li><p>Difficult to use with generics</p>
</li>
<li><p>Can lead to confusing inference in larger codebases</p>
</li>
</ul>
<p><strong>Recommended Approach:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Props = { title: <span class="hljs-built_in">string</span> };
<span class="hljs-keyword">const</span> Card = <span class="hljs-function">(<span class="hljs-params">{ title }: Props</span>) =&gt;</span> &lt;div&gt;{title}&lt;/div&gt;;
</code></pre>
<p>This is explicit, safer, and more maintainable.</p>
<h2 id="heading-typescript-mistakes">Typescript Mistakes</h2>
<p>In this section, we’ll explore <strong>common mistakes TypeScript developers make</strong> and provide <strong>practical solutions</strong> to avoid or fix them.</p>
<h3 id="heading-using-any-excessively">Using any Excessively</h3>
<p><strong>Mistake</strong></p>
<p>Overusing <code>any</code> removes type safety, making your code prone to runtime errors.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> data: <span class="hljs-built_in">any</span>;
data = <span class="hljs-string">"Hello"</span>;
data = <span class="hljs-number">42</span>; <span class="hljs-comment">// No type checking</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> data: unknown;
data = <span class="hljs-string">"Hello"</span>;
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> data === <span class="hljs-string">"string"</span>) {
  <span class="hljs-built_in">console</span>.log(data.toUpperCase()); <span class="hljs-comment">// Safe to use</span>
}
</code></pre>
<h3 id="heading-ignoring-strict-compiler-options">Ignoring Strict Compiler Options</h3>
<p><strong>Mistake</strong></p>
<p>Not enabling strict mode weakens TypeScript’s type checking.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript">{
  <span class="hljs-string">"compilerOptions"</span>: {
    <span class="hljs-string">"strict"</span>: <span class="hljs-literal">false</span>
  }
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript">{
  <span class="hljs-string">"compilerOptions"</span>: {
    <span class="hljs-string">"strict"</span>: <span class="hljs-literal">true</span>
  }
}
</code></pre>
<h3 id="heading-not-using-type-inference">Not Using Type Inference</h3>
<p><strong>Mistake</strong></p>
<p>Explicitly typing everything, even when TypeScript can infer it.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> count: <span class="hljs-built_in">number</span> = <span class="hljs-number">0</span>;
<span class="hljs-keyword">let</span> name: <span class="hljs-built_in">string</span> = <span class="hljs-string">"John"</span>;
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span>; <span class="hljs-comment">// TypeScript infers `number`</span>
<span class="hljs-keyword">let</span> name = <span class="hljs-string">"John"</span>; <span class="hljs-comment">// TypeScript infers `string`</span>
</code></pre>
<h3 id="heading-overusing-non-null-assertions"><strong>Overusing Non-Null Assertions (</strong><code>!</code>)</h3>
<p><strong>Mistake</strong></p>
<p>Using <code>!</code> to assert non-null values without proper checks.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> element = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"myElement"</span>)!;
element.click(); <span class="hljs-comment">// Risky</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> element = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"myElement"</span>);
<span class="hljs-keyword">if</span> (element) {
  element.click(); <span class="hljs-comment">// Safe</span>
}
</code></pre>
<h3 id="heading-not-handling-undefined-or-null-properly"><strong>Not Handling</strong> <code>undefined</code> or <code>null</code> Properly</h3>
<p><strong>Mistake</strong></p>
<p>Ignoring potential <code>undefined</code> or <code>null</code> values.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> name = user.profile.name; <span class="hljs-comment">// Could throw an error</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> name = user?.profile?.name ?? <span class="hljs-string">"Default Name"</span>; <span class="hljs-comment">// Safe</span>
</code></pre>
<h3 id="heading-misusing-enums">Misusing Enums</h3>
<p><strong>Mistake</strong></p>
<p>Using enums when a union type would suffice.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-built_in">enum</span> Status {
  Active,
  Inactive,
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Status = <span class="hljs-string">"active"</span> | <span class="hljs-string">"inactive"</span>;
</code></pre>
<h3 id="heading-not-leveraging-utility-types">Not Leveraging Utility Types</h3>
<p><strong>Mistake</strong></p>
<p>Manually creating types when utility types could simplify your code.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> User {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> UserPreview {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> UserPreview = Pick&lt;User, <span class="hljs-string">"id"</span> | <span class="hljs-string">"name"</span>&gt;;
</code></pre>
<h3 id="heading-ignoring-readonly-for-immutability"><strong>Ignoring</strong> <code>readonly</code> for Immutability</h3>
<p><strong>Mistake</strong></p>
<p>Not marking properties as <code>readonly</code> when they shouldn’t change.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Config {
  apiUrl: <span class="hljs-built_in">string</span>;
}
<span class="hljs-keyword">const</span> config: Config = { apiUrl: <span class="hljs-string">"https://api.example.com"</span> };
config.apiUrl = <span class="hljs-string">"https://malicious.com"</span>; <span class="hljs-comment">// Mutated</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Config {
  <span class="hljs-keyword">readonly</span> apiUrl: <span class="hljs-built_in">string</span>;
}
<span class="hljs-keyword">const</span> config: Config = { apiUrl: <span class="hljs-string">"https://api.example.com"</span> };
<span class="hljs-comment">// config.apiUrl = "https://malicious.com"; // Error: Cannot assign to 'apiUrl'</span>
</code></pre>
<h3 id="heading-not-using-generics-effectively">Not Using Generics Effectively</h3>
<p><strong>Mistake</strong></p>
<p>Writing repetitive code instead of using generics.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">identityNumber</span>(<span class="hljs-params">num: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">number</span> </span>{
  <span class="hljs-keyword">return</span> num;
}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">identityString</span>(<span class="hljs-params">str: <span class="hljs-built_in">string</span></span>): <span class="hljs-title">string</span> </span>{
  <span class="hljs-keyword">return</span> str;
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">identity</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">value: T</span>): <span class="hljs-title">T</span> </span>{
  <span class="hljs-keyword">return</span> value;
}
</code></pre>
<h3 id="heading-ignoring-interface-vs-type-differences"><strong>Ignoring</strong> <code>interface</code> vs <code>type</code> Differences</h3>
<p><strong>Mistake</strong></p>
<p>Using <code>interface</code> and <code>type</code> interchangeably without understanding their differences.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> User = {
  name: <span class="hljs-built_in">string</span>;
};
<span class="hljs-keyword">type</span> Admin = User &amp; { role: <span class="hljs-built_in">string</span> }; <span class="hljs-comment">// Works, but `interface` is better for object shapes</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> User {
  name: <span class="hljs-built_in">string</span>;
}
<span class="hljs-keyword">interface</span> Admin <span class="hljs-keyword">extends</span> User {
  role: <span class="hljs-built_in">string</span>;
}
</code></pre>
<h3 id="heading-not-using-as-const-for-literal-types"><strong>Not Using</strong> <code>as const</code> for Literal Types</h3>
<p><strong>Mistake</strong></p>
<p>Not preserving literal types when needed.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> colors = [<span class="hljs-string">"red"</span>, <span class="hljs-string">"green"</span>, <span class="hljs-string">"blue"</span>]; <span class="hljs-comment">// Type: string[]</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> colors = [<span class="hljs-string">"red"</span>, <span class="hljs-string">"green"</span>, <span class="hljs-string">"blue"</span>] <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>; <span class="hljs-comment">// Type: readonly ["red", "green", "blue"]</span>
</code></pre>
<h3 id="heading-not-handling-async-code-properly">Not Handling Async Code Properly</h3>
<p><strong>Mistake</strong></p>
<p>Forgetting to handle promises or using <code>any</code> for async results.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">any</span>&gt; </span>{
  <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">"/api/data"</span>);
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>): <span class="hljs-title">Promise</span>&lt;<span class="hljs-title">MyDataType</span>&gt; </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/data"</span>);
  <span class="hljs-keyword">return</span> response.json();
}
</code></pre>
<h3 id="heading-not-using-type-guards">Not Using Type Guards</h3>
<p><strong>Mistake</strong></p>
<p>Not narrowing types with type guards.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printValue</span>(<span class="hljs-params">value: unknown</span>) </span>{
  <span class="hljs-built_in">console</span>.log(value.toUpperCase()); <span class="hljs-comment">// Error: 'value' is of type 'unknown'</span>
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isString</span>(<span class="hljs-params">value: unknown</span>): <span class="hljs-title">value</span> <span class="hljs-title">is</span> <span class="hljs-title">string</span> </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"string"</span>;
}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">printValue</span>(<span class="hljs-params">value: unknown</span>) </span>{
  <span class="hljs-keyword">if</span> (isString(value)) {
    <span class="hljs-built_in">console</span>.log(value.toUpperCase()); <span class="hljs-comment">// Safe</span>
  }
}
</code></pre>
<h3 id="heading-ignoring-tsconfigjson-settings"><strong>Ignoring</strong> <code>tsconfig.json</code> Settings</h3>
<p><strong>Mistake</strong></p>
<p>Not configuring <code>tsconfig.json</code> properly.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript">{
  <span class="hljs-string">"compilerOptions"</span>: {
    <span class="hljs-string">"target"</span>: <span class="hljs-string">"ES5"</span>
  }
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript">{
  <span class="hljs-string">"compilerOptions"</span>: {
    <span class="hljs-string">"target"</span>: <span class="hljs-string">"ES2022"</span>,
    <span class="hljs-string">"module"</span>: <span class="hljs-string">"ESNext"</span>,
    <span class="hljs-string">"outDir"</span>: <span class="hljs-string">"./dist"</span>,
    <span class="hljs-string">"rootDir"</span>: <span class="hljs-string">"./src"</span>,
    <span class="hljs-string">"strict"</span>: <span class="hljs-literal">true</span>
  }
}
</code></pre>
<h3 id="heading-not-writing-tests-for-types">Not Writing Tests for Types</h3>
<p><strong>Mistake</strong></p>
<p>Assuming types are correct without testing them.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span>(<span class="hljs-params">a: <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">number</span> </span>{
  <span class="hljs-keyword">return</span> a + b;
}
<span class="hljs-comment">// No type tests</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { expectType } <span class="hljs-keyword">from</span> <span class="hljs-string">"tsd"</span>;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span>(<span class="hljs-params">a: <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">number</span> </span>{
  <span class="hljs-keyword">return</span> a + b;
}
expectType&lt;<span class="hljs-built_in">number</span>&gt;(add(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)); <span class="hljs-comment">// Passes</span>
expectType&lt;<span class="hljs-built_in">string</span>&gt;(add(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)); <span class="hljs-comment">// Fails</span>
</code></pre>
<h3 id="heading-not-using-keyof-for-type-safe-object-keys"><strong>Not Using</strong> <code>keyof</code> for Type-Safe Object Keys</h3>
<p><strong>Mistake</strong></p>
<p>Accessing object keys without type safety can lead to runtime errors.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getValue</span>(<span class="hljs-params">obj: <span class="hljs-built_in">any</span>, key: <span class="hljs-built_in">string</span></span>) </span>{
  <span class="hljs-keyword">return</span> obj[key]; <span class="hljs-comment">// No type safety</span>
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getValue</span>&lt;<span class="hljs-title">T</span>, <span class="hljs-title">K</span> <span class="hljs-title">extends</span> <span class="hljs-title">keyof</span> <span class="hljs-title">T</span>&gt;(<span class="hljs-params">obj: T, key: K</span>) </span>{
  <span class="hljs-keyword">return</span> obj[key]; <span class="hljs-comment">// Type-safe</span>
}
</code></pre>
<h3 id="heading-ignoring-never-for-exhaustiveness-checking"><strong>Ignoring</strong> <code>never</code> for Exhaustiveness Checking</h3>
<p><strong>Mistake</strong></p>
<p>Not using <code>never</code> to ensure all cases are handled in a union type.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Shape = <span class="hljs-string">"circle"</span> | <span class="hljs-string">"square"</span>;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getArea</span>(<span class="hljs-params">shape: Shape</span>) </span>{
  <span class="hljs-keyword">if</span> (shape === <span class="hljs-string">"circle"</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.PI * <span class="hljs-number">2</span> ** <span class="hljs-number">2</span>;
  }
  <span class="hljs-comment">// Forgot to handle "square"</span>
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getArea</span>(<span class="hljs-params">shape: Shape</span>) </span>{
  <span class="hljs-keyword">if</span> (shape === <span class="hljs-string">"circle"</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.PI * <span class="hljs-number">2</span> ** <span class="hljs-number">2</span>;
  }
  <span class="hljs-keyword">if</span> (shape === <span class="hljs-string">"square"</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-number">4</span> ** <span class="hljs-number">2</span>;
  }
  <span class="hljs-keyword">const</span> _exhaustiveCheck: <span class="hljs-built_in">never</span> = shape; <span class="hljs-comment">// Ensures all cases are handled</span>
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Unknown shape: <span class="hljs-subst">${shape}</span>`</span>);
}
</code></pre>
<h3 id="heading-not-using-mapped-types">Not Using Mapped Types</h3>
<p><strong>Mistake</strong></p>
<p>Manually creating similar types instead of using mapped types.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> User {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> OptionalUser {
  id?: <span class="hljs-built_in">number</span>;
  name?: <span class="hljs-built_in">string</span>;
  email?: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> OptionalUser = Partial&lt;User&gt;;
</code></pre>
<h3 id="heading-not-using-satisfies-for-type-validation"><strong>Not Using</strong> <code>satisfies</code> for Type Validation</h3>
<p><strong>Mistake</strong></p>
<p>Not validating that an object satisfies a specific type.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> user = {
  id: <span class="hljs-number">1</span>,
  name: <span class="hljs-string">"John"</span>,
  <span class="hljs-comment">// Missing `email`</span>
};
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> user = {
  id: <span class="hljs-number">1</span>,
  name: <span class="hljs-string">"John"</span>,
  email: <span class="hljs-string">"john@example.com"</span>,
} satisfies User; <span class="hljs-comment">// Ensures `user` matches `User` type</span>
</code></pre>
<h3 id="heading-not-using-infer-in-conditional-types"><strong>Not Using</strong> <code>infer</code> in Conditional Types</h3>
<p><strong>Mistake</strong></p>
<p>Not leveraging <code>infer</code> to extract types dynamically.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> GetReturnType&lt;T&gt; = T <span class="hljs-keyword">extends</span> (...args: <span class="hljs-built_in">any</span>[]) =&gt; <span class="hljs-built_in">any</span> ? <span class="hljs-built_in">any</span> : <span class="hljs-built_in">never</span>;
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> GetReturnType&lt;T&gt; = T <span class="hljs-keyword">extends</span> (...args: <span class="hljs-built_in">any</span>[]) =&gt; infer R ? R : <span class="hljs-built_in">never</span>;
</code></pre>
<h3 id="heading-not-using-declare-for-ambient-declarations"><strong>Not Using</strong> <code>declare</code> for Ambient Declarations</h3>
<p><strong>Mistake</strong></p>
<p>Not using <code>declare</code> for external libraries or global variables.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> $ = jQuery; <span class="hljs-comment">// No type information</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">const</span> $: <span class="hljs-keyword">typeof</span> jQuery; <span class="hljs-comment">// Provides type information</span>
</code></pre>
<h3 id="heading-not-using-const-assertions-for-immutable-arraysobjects"><strong>Not Using</strong> <code>const</code> Assertions for Immutable Arrays/Objects</h3>
<p><strong>Mistake</strong></p>
<p>Not using <code>const</code> assertions to make arrays or objects immutable.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> colors = [<span class="hljs-string">"red"</span>, <span class="hljs-string">"green"</span>, <span class="hljs-string">"blue"</span>];
colors.push(<span class="hljs-string">"yellow"</span>); <span class="hljs-comment">// Allowed</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> colors = [<span class="hljs-string">"red"</span>, <span class="hljs-string">"green"</span>, <span class="hljs-string">"blue"</span>] <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;
<span class="hljs-comment">// colors.push("yellow"); // Error: Property 'push' does not exist</span>
</code></pre>
<h3 id="heading-not-using-this-parameter-in-callbacks"><strong>Not Using</strong> <code>this</code> Parameter in Callbacks</h3>
<p><strong>Mistake</strong></p>
<p>Not binding <code>this</code> in callbacks, leading to unexpected behavior.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Button {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-built_in">this</span>.element.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-built_in">this</span>.handleClick);
  }
  handleClick() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>); <span class="hljs-comment">// `this` is undefined</span>
  }
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Button {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-built_in">this</span>.element.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-built_in">this</span>.handleClick.bind(<span class="hljs-built_in">this</span>));
  }
  handleClick() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>); <span class="hljs-comment">// `this` refers to the Button instance</span>
  }
}
</code></pre>
<h3 id="heading-not-using-record-for-dictionary-like-objects"><strong>Not Using</strong> <code>Record</code> for Dictionary-Like Objects</h3>
<p><strong>Mistake</strong></p>
<p>Using <code>any</code> or loose types for dictionary-like objects.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> users: { [key: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">any</span> } = {
  <span class="hljs-string">"1"</span>: { name: <span class="hljs-string">"John"</span> },
  <span class="hljs-string">"2"</span>: { name: <span class="hljs-string">"Jane"</span> },
};
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> users: Record&lt;<span class="hljs-built_in">string</span>, { name: <span class="hljs-built_in">string</span> }&gt; = {
  <span class="hljs-string">"1"</span>: { name: <span class="hljs-string">"John"</span> },
  <span class="hljs-string">"2"</span>: { name: <span class="hljs-string">"Jane"</span> },
};
</code></pre>
<h3 id="heading-not-using-awaited-for-unwrapping-promises"><strong>Not Using</strong> <code>Awaited</code> for Unwrapping Promises</h3>
<p><strong>Mistake</strong></p>
<p>Not properly unwrapping nested promises.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Result = <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt;&gt;; <span class="hljs-comment">// Nested promises</span>
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> Result = Awaited&lt;<span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span>&gt;&gt;&gt;; <span class="hljs-comment">// Unwraps to `string`</span>
</code></pre>
<h3 id="heading-not-using-unknown-for-catch-clauses"><strong>Not Using</strong> <code>unknown</code> for Catch Clauses</h3>
<p><strong>Mistake</strong></p>
<p>Using <code>any</code> for <code>catch</code> clauses, which can hide errors.</p>
<p><strong>Bad</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">try</span> {
  <span class="hljs-comment">// Some code</span>
} <span class="hljs-keyword">catch</span> (error: <span class="hljs-built_in">any</span>) {
  <span class="hljs-built_in">console</span>.log(error.message); <span class="hljs-comment">// Unsafe</span>
}
</code></pre>
<p><strong>Good</strong></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">try</span> {
  <span class="hljs-comment">// Some code</span>
} <span class="hljs-keyword">catch</span> (error: unknown) {
  <span class="hljs-keyword">if</span> (error <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Error</span>) {
    <span class="hljs-built_in">console</span>.log(error.message); <span class="hljs-comment">// Safe</span>
  }
}
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>I hope that you have found this article helpful and that it has inspired you to become a better Typescript developer.</p>
<p>Happy coding ❤️</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://www.totaltypescript.com/pass-component-as-prop-react#passing-any-component-as-a-prop-and-inferring-its-props">http</a><a target="_blank" href="https://www.totaltypescript.com/">s://blog.logrocket.com/ty</a><a target="_blank" href="https://blog.logrocket.com/types-vs-interfaces-typescript/?ref=dailydev">pes-vs-interfaces-typescript</a></p>
<p><a target="_blank" href="https://dev.to/sachinchaurasiya/type-safety-in-typescript-unknown-vs-any-55c0?context=digest">https://dev</a><a target="_blank" href="https://react.dev/reference/react/Children#calling-a-render-prop-to-customize-rendering">.to/sachinchaurasiya/type-sa</a><a target="_blank" href="https://dev.to/sachinchaurasiya/type-safety-in-typescript-unknown-vs-any-55c0?context=digest">fety-in-typescript-unknown-vs-any-55c</a><a target="_blank" href="https://www.totaltypescript.com/pass-component-as-prop-react#passing-any-component-as-a-prop-and-inferring-its-props">0?context=digest</a></p>
<p><a target="_blank" href="https://www.totaltypescript.com/pass-component-as-prop-react#passing-any-component-as-a-prop-and-inferring-its-props">https://dev.to/zacharylee/the-differences-betw</a><a target="_blank" href="https://dev.to/zacharylee/the-differences-between-object-and-object-in-typescript-f6f?context=digest">een-object-and-object-in-typescript-f6f?context=digest</a></p>
<p><a target="_blank" href="https://itnext.io/mastering-typescript-21-best-practices-for-improved-code-quality-2f7615e1fdc3">https://itnext.io/mas</a><a target="_blank" href="https://www.mattpocock.com/">tering-typescript-21</a><a target="_blank" href="https://itnext.io/mastering-typescript-21-best-practices-for-improved-code-quality-2f7615e1fdc3">-best-pract</a><a target="_blank" href="https://www.totaltypescript.com/">ices-for-improved-code-qu</a><a target="_blank" href="https://itnext.io/mastering-typescript-21-best-practices-for-improved-code-quality-2f7615e1fdc3">ality-2f7615e1fdc3</a></p>
<p><a target="_blank" href="https://programming.earthonline.us/what-are-k-t-and-v-in-typescript-generics-9fabe1d0f0f3">https://programming.earthonline.us/what-are-k-t-and-v-in-typescript-generics-9fabe1d0f</a><a target="_blank" href="https://www.totaltypescript.com/pass-component-as-prop-react#passing-any-component-as-a-prop-and-inferring-its-props">0f3</a></p>
<p><a target="_blank" href="https://www.totaltypescript.com/pass-component-as-prop-react#passing-any-component-as-a-prop-and-inferring-its-props">https://programming.earthonline.us/with-these-articles-you-</a><a target="_blank" href="https://programming.earthonline.us/with-these-articles-you-will-not-be-confused-when-learning-typescript-d96a5c99e229#16ee">will-not-be-confused-when-learning-typescript-d96a5c99e229#16ee</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/5-very-useful-tricks-for-thetypescript-typeof-operator-404c0d30cd5">https://javascript.plainenglish.io/5-very-useful-tricks-for-thetypescript-typeof-operator-404c0d30cd5</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/how-to-make-your-typescript-code-more-elegant-73645401b9b1">https://javascript.plainenglish.io/how-to-make-your-typescript-code-more-elegant-73645401b9b1</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/typescript-index-signature-explained-b040a78a0467">https://levelup.gitconnected.com/typescript-index-signature-explained-b040a78a0467</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/typescript-type-guards-in-6-minutes-9a9bab7fbe78">https://levelup.gitconnected.com/typescript-type-guards-in-6-minutes-9a9bab7fbe78</a></p>
<p><a target="_blank" href="https://ramkumarkhub.medium.com/advanced-typescript-patterns-that-will-make-you-a-better-javascript-developer-3accccc3fc78">https://ramkumarkhub.medium.com/advanced-typescript-patterns-that-will-make-you-a-better-javascript-developer-3accccc3fc78</a></p>
<p><a target="_blank" href="https://lakin-mohapatra.medium.com/top-30-mistakes-typescript-developers-make-and-how-to-avoid-them-59899f95615a">https://lakin-mohapatra.medium.com/top-30-mistakes-typescript-developers-make-and-how-to-avoid-them-59899f95615a</a></p>
<p><a target="_blank" href="https://medium.com/web-tech-journals/advanced-typescript-techniques-for-react-developers-write-safer-smarter-components-360ec076125f">https://medium.com/web-tech-journals/advanced-typescript-techniques-for-react-developers-write-safer-smarter-components-360ec076125f</a></p>
<p><a target="_blank" href="https://medium.com/the-syntax-diaries/typescript-types-that-scared-me-until-i-learned-these-3-rules-34f8ea09ecb2">https://medium.com/the-syntax-diaries/typescript-types-that-scared-me-until-i-learned-these-3-rules-34f8ea09ecb2</a></p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/learn-object-oriented-programming-in-typescript/?ref=dailydev">https://www.freecodecamp.org/news/learn-object-oriented-programming-in-typescript/?ref=dailydev</a></p>
<p><a target="_blank" href="https://medium.com/codetodeploy/time-is-money-the-typescript-patterns-that-tripled-my-productivity-and-will-transform-yours-32088c876c80">https://medium.com/codetodeploy/time-is-money-the-typescript-patterns-that-tripled-my-productivity-and-will-transform-yours-32088c876c80</a></p>
<p><a target="_blank" href="https://medium.com/codetodeploy/the-dead-simple-typescript-trick-that-saved-me-15-hours-of-debugging-hell-and-why-youre-probably-a62e3aef8b8b">https://medium.com/codetodeploy/the-dead-simple-typescript-trick-that-saved-me-15-hours-of-debugging-hell-and-why-youre-probably-a62e3aef8b8b</a></p>
]]></content:encoded></item><item><title><![CDATA[Design Patterns Handbook - Part IV]]></title><description><![CDATA[Let's explore the remaining 5 Behavioral Design Patterns.
The Observer Pattern


Observer is a behavioral design pattern that lets you define a subscription machanism to notify multiple objects about any events that happen to the object they are obse...]]></description><link>https://blog.tuanhadev.tech/design-patterns-handbook-part-iv</link><guid isPermaLink="true">https://blog.tuanhadev.tech/design-patterns-handbook-part-iv</guid><category><![CDATA[design patterns]]></category><category><![CDATA[Behavioral Design Pattern]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[Object Relationship]]></category><category><![CDATA[code organization]]></category><category><![CDATA[code maintainability]]></category><category><![CDATA[Scalable web applications]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Mon, 30 Sep 2024 10:44:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/zui8p1VRjzk/upload/072b109f04f47d43931996b3a6e44189.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let's explore the remaining 5 Behavioral Design Patterns.</p>
<h2 id="heading-the-observer-pattern">The Observer Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725106680807/8ce7f1c1-5a6c-4a71-aa6d-7b64704d65fc.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Observer</strong> is a behavioral design pattern that lets you define a subscription machanism to notify multiple objects about any events that happen to the object they are observing.</p>
</blockquote>
<h3 id="heading-problem">Problem</h3>
<p>Imagine you have two types of objects: a Customer and a Store. The customer is very interested in a particular brand of product(say, it’s a new model of the iPhone) which should become available in the store very soon.</p>
<p>The customer could visit the store every day and check product availability. But while the product is still en route, most of these trips would be pointless.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726283426723/8b3564df-795c-48f7-b695-18625b4b4576.png" alt class="image--center mx-auto" /></p>
<p>On the other hand, the store could send tons of emails (which might be considered spam) to all customers each time a new product becomes available. This would save some customers from endless trips to the store. At the same time, it would upset other customers who aren’t interested in new products.</p>
<p>It looks like we have got a conflict. Either the customer wastes time checking product availability or the store wastes resources notifying the wrong customers.</p>
<h3 id="heading-solution">Solution</h3>
<p>The object that has some interesting state is often called the <em>subject,</em> but since it’s also going to notify other objects about the changes to its state, we will call it the <em>publisher</em>. All other objects that want to track changes to the publisher’s state are called <em>subscribers</em>.</p>
<p>The Observer pattern suggests that you add a subscription mechanism to the publisher class so individual subjects can subscribe to or unsubscribe from a stream of events coming from that publisher. Fear not! Everything isn’t as complicated as it sounds. In reality, this mechanism consists of 1 ) an array field for storing a list of references to subscriber objects and 2) several public methods that allow adding subscribers to and removing them from that list.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726285687786/6e546841-d3e1-47ae-b3dd-444c283ac603.png" alt class="image--center mx-auto" /></p>
<p>Now, whenever an important event happens to the publisher, it goes over its subscribers and calls the specific notification method on their objects.</p>
<p>Real apps might have dozens of different subscriber classes that are interested in tracking events on the same publisher class. You wouldn’t want to couple the publisher to all of those classes. Besides, you might not even know about some of them beforehand if your publisher class is supposed to be used by other people.</p>
<p>That’s why it’s crucial that all subscribers implement the same interface and that the publisher communicates with them only via that interface. This interface should declare the notification method along with a set of parameters that the publisher can use to pass some contextual data along with the notification.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726286371892/647ff555-92f9-4d33-a1ce-43a26b6a1f77.png" alt class="image--center mx-auto" /></p>
<p>if your app has several different types of publishers and you want to make your subscribers compatible with all of them, you can go even further and make all publishers follow the same interface. This interface would only need to describe a few subscription methods. The interface would allow subscribers to observe publishers’ states without coupling them to their concrete classes.</p>
<h3 id="heading-real-world-analogy">Real-World Analogy</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726287056949/654a7c72-98ec-4790-bb7b-eb2c2a373332.png" alt class="image--center mx-auto" /></p>
<p>if you subscribe to a newspaper or magazine, you no longer need to go to the store to check if the next issue is available. Instead, the publisher sends new issues to your mailbox right after publication or even in advance.</p>
<p>The publisher maintains a list of subscribers and knows which magazines they are interested in. Subscribers can leave the list at any time when they wish to stop the publisher from sending them new magazine issues.</p>
<h3 id="heading-example">Example</h3>
<p>In this first example, we are going to translate the theoretical UML diagram into Typescript to test the potential of this pattern. This is the diagram to be implemented:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726304150057/bd67f4b5-cddf-4719-84ec-aa441ddcdbad.png" alt class="image--center mx-auto" /></p>
<p>First, we are going to define the interface (<code>Subject</code>) of our problem. Being an interface, all the methods that must be implemented in all the specific <code>Subject</code> are defined. In our case, there is only one: <code>ConcreteSubject</code>. The <code>Subject</code> interface defines the three methods necessary to comply with this pattern: <code>attach</code>, <code>detach</code>, and <code>notify</code>. The <code>attach</code> and <code>detach</code> methods receive the <code>observer</code> as a parameter that will be added or removed in the <code>Subject</code> data structure.</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">import</span> { Observer } <span class="hljs-keyword">from</span> <span class="hljs-string">"./observer.interface"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Subject {
  attach(observer: Observer): <span class="hljs-built_in">void</span>;
  detach(observer: Observer): <span class="hljs-built_in">void</span>;
  notify(): <span class="hljs-built_in">void</span>;
}
</code></pre>
<p>There can be as many <code>ConcreteSubjects</code> as we need in our problem. As this problem is the basic scheme of the Observer pattern, we only need a single <code>ConcreteSubject</code>. In this first problem, the state that is observed is the <code>state</code> attribute, which is of type <code>number</code>. On the other hand, all <code>observers</code> are stored in an array called <code>observer</code>. The <code>attach</code> and <code>detach</code> methods check whether or not the <code>observer</code> is previously in the data structure to add or remove it from it. Finally, the <code>notify</code> method is in charge of invoking the <code>update</code> method of all those <code>observers</code> who are observing the <code>Subject</code>.</p>
<p>Objects of the <code>ConcreteSubject</code> the class performs some tasks related to the specific business logic of each problem. In this example, there is a method called <code>operation</code> that is in charge of modifying the <code>state</code> and invoking the <code>notify</code> method.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Observer } <span class="hljs-keyword">from</span> <span class="hljs-string">"./observer.interface"</span>;
<span class="hljs-keyword">import</span> { Subject } <span class="hljs-keyword">from</span> <span class="hljs-string">"./subject.interface"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ConcreteSubject <span class="hljs-keyword">implements</span> Subject {
  <span class="hljs-keyword">public</span> state: <span class="hljs-built_in">number</span>;
  <span class="hljs-keyword">private</span> observers: Observer[] = [];

  <span class="hljs-keyword">public</span> attach(observer: Observer): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">const</span> isAttached = <span class="hljs-built_in">this</span>.observers.includes(observer);
    <span class="hljs-keyword">if</span> (isAttached) {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Subject: Observer has been attached already"</span>);
    }

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Subject: Attached an observer."</span>);
    <span class="hljs-built_in">this</span>.observers.push(observer);
  }

  <span class="hljs-keyword">public</span> detach(observer: Observer): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">const</span> observerIndex = <span class="hljs-built_in">this</span>.observers.indexOf(observer);
    <span class="hljs-keyword">if</span> (observerIndex === <span class="hljs-number">-1</span>) {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Subject: Nonexistent observer"</span>);
    }

    <span class="hljs-built_in">this</span>.observers.splice(observerIndex, <span class="hljs-number">1</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Subject: Detached an observer"</span>);
  }

  <span class="hljs-keyword">public</span> notify(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Subject: Notifying observers..."</span>);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> observer <span class="hljs-keyword">of</span> <span class="hljs-built_in">this</span>.observers) {
      observer.update(<span class="hljs-built_in">this</span>);
    }
  }

  <span class="hljs-keyword">public</span> operation(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Subject: Business Logic."</span>);
    <span class="hljs-built_in">this</span>.state = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * (<span class="hljs-number">10</span> + <span class="hljs-number">1</span>));

    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Subject: The state has just changed to: <span class="hljs-subst">${<span class="hljs-built_in">this</span>.state}</span>`</span>);
    <span class="hljs-built_in">this</span>.notify();
  }
}
</code></pre>
<p>The other piece of this design pattern is the <code>observer</code>. Therefore, let’s start by defining the <code>Observer</code> interface, which only needs to define the <code>update</code> method that is in charge of executing every time an <code>observer</code> is notified that a change has occurred.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Subject } <span class="hljs-keyword">from</span> <span class="hljs-string">"./subject.interface"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Observer {
  update(subject: Subject): <span class="hljs-built_in">void</span>;
}
</code></pre>
<p>Each class that implements this interface must include its business logic in the <code>update</code> method. In this example, two <code>ConcreteObservers</code> have been defined. They will perform actions according to the <code>Subject</code>’s <code>state</code>. The following code shows two concrete implementations for two different types of observers: <code>ConcreteObserverA</code> and <code>ConcreteObserverB</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ConcreteSubject } <span class="hljs-keyword">from</span> <span class="hljs-string">"./concrete-subject"</span>;
<span class="hljs-keyword">import</span> { Observer } <span class="hljs-keyword">from</span> <span class="hljs-string">"./observer.interface"</span>;
<span class="hljs-keyword">import</span> { Subject } <span class="hljs-keyword">from</span> <span class="hljs-string">"./subject.interface"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ConcreteObserverA <span class="hljs-keyword">implements</span> Observer {
  <span class="hljs-keyword">public</span> update(subject: Subject): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (subject <span class="hljs-keyword">instanceof</span> ConcreteSubject &amp;&amp; subject.state &lt; <span class="hljs-number">3</span>) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"ConcreteObserverA: Reacted to the event."</span>);
    }
  }
}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ConcreteSubject } <span class="hljs-keyword">from</span> <span class="hljs-string">"./concrete-subject"</span>;
<span class="hljs-keyword">import</span> { Observer } <span class="hljs-keyword">from</span> <span class="hljs-string">"./observer.interface"</span>;
<span class="hljs-keyword">import</span> { Subject } <span class="hljs-keyword">from</span> <span class="hljs-string">"./subject.interface"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ConcreteObserverB <span class="hljs-keyword">implements</span> Observer {
  <span class="hljs-keyword">public</span> update(subject: Subject): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (
      subject <span class="hljs-keyword">instanceof</span> ConcreteSubject &amp;&amp;
      (subject.state === <span class="hljs-number">0</span> || subject.state &gt;= <span class="hljs-number">2</span>)
    ) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"ConcreteObserverB: Reacted to the event."</span>);
    }
  }
}
</code></pre>
<p>Finally, we define our <code>Client</code> or <code>Context</code> the class that makes use of this pattern. In the following code, the necessary classes to simulate the use of <code>Subject</code> and <code>Observer</code> are implemented:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ConcreteObserverA } <span class="hljs-keyword">from</span> <span class="hljs-string">"./concrete-observerA"</span>;
<span class="hljs-keyword">import</span> { ConcreteObserverB } <span class="hljs-keyword">from</span> <span class="hljs-string">"./concrete-observerB"</span>;
<span class="hljs-keyword">import</span> { ConcreteSubject } <span class="hljs-keyword">from</span> <span class="hljs-string">"./concrete-subject"</span>;

<span class="hljs-keyword">const</span> subject = <span class="hljs-keyword">new</span> ConcreteSubject();

<span class="hljs-keyword">const</span> observer1 = <span class="hljs-keyword">new</span> ConcreteObserverA();
subject.attach(observer1);

<span class="hljs-keyword">const</span> observer2 = <span class="hljs-keyword">new</span> ConcreteObserverB();
subject.attach(observer2);

subject.operation();
subject.operation();

subject.detach(observer2);

subject.operation();
</code></pre>
<h2 id="heading-the-state-pattern">The State Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726306208937/feeb183c-ef48-411a-9b0e-f7e717a1c7d9.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>State</strong> is a behavioral design pattern that lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/state">https://refactoring.guru/design-patterns/state</a></p>
</blockquote>
<h3 id="heading-problem-1">Problem</h3>
<p>The State pattern is closely related to the concept of a Finite-State Machine.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727083201397/b47633a7-d351-420e-ab67-0c2d35553399.png" alt class="image--center mx-auto" /></p>
<p>The main idea is that, at any given moment, there is a finite number of states in which a program can be implemented. Within any unique update, the program behaves differently, and the program can be switched from one state to another instantaneously. However, depending on the current state, the program may or may not switch to certain other states. These switching rules, called transitions, are also finite and predetermined.</p>
<p>You can also apply this approach to objects. Imagine that we have a <code>Document</code> class. A document can be in one of three states: Draft, Moderation, and <code>Published</code>. The <code>publish</code> method of the document works a bit differently in each state.</p>
<ul>
<li><p>In <code>Draft</code>, it moves the document to moderation.</p>
</li>
<li><p>In <code>Moderation</code>, it makes the document public, but only the current user is an administrator.</p>
</li>
<li><p>In <code>Published</code>, it doesn't do anything at all.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727084217735/cb86650f-f24d-4c12-862a-f1c8b46cd72e.png" alt class="image--center mx-auto" /></p>
<p>State machines are usually implemented with lots of conditional statements(<code>if</code> or <code>switch</code>) that select the appropriate behavior depending on the current state of the object. Usually, this “state“ is just a set of values of the object’s fields. Even if you have never heard about finite-state machines before, you have probably implemented a state at least once. Does the following code structure ring a bell?</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Document is
    field state: <span class="hljs-built_in">string</span>
    <span class="hljs-comment">// ...</span>
    method publish() is
        <span class="hljs-keyword">switch</span> (state)
            <span class="hljs-string">"draft"</span>:
                state = <span class="hljs-string">"moderation"</span>
                <span class="hljs-keyword">break</span>
            <span class="hljs-string">"moderation"</span>:
                <span class="hljs-keyword">if</span> (currentUser.role == <span class="hljs-string">"admin"</span>)
                    state = <span class="hljs-string">"published"</span>
                <span class="hljs-keyword">break</span>
            <span class="hljs-string">"published"</span>:
                <span class="hljs-comment">// Do nothing.</span>
                <span class="hljs-keyword">break</span>
    <span class="hljs-comment">// ...</span>
</code></pre>
<p>The biggest weakness of a state machine based on conditionals reveals itself once we start adding more and more states and state-dependent behaviors to the <code>Document</code> class. Most methods will contain monstrous conditionals that pick the proper behavior of a method according to the current state. Code like this is very difficult to maintain because any change to the transition logic may require changing state conditionals in every method.</p>
<p>The project tends to get bigger as a project evolves. It’s quite difficult to predict all possible states or transitions that the design state. Hence, a lean state machine built with a limited set of conditionals can grow into a bloated mess over time.</p>
<h3 id="heading-solution-1">Solution</h3>
<p>The State pattern suggests that you create new classes for all possible states of an object and extract all state-specific behaviors into these classes.</p>
<p>Instead of implementing all behaviors on its own, the original object called <em>context,</em> stores a reference to one of the state objects that represents its current state and delegates all state-related work to that project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727087548971/28a84bef-7b99-4058-bfbc-42a0840600c5.png" alt class="image--center mx-auto" /></p>
<p>To transition the context into another state, replace the active state object with another object that represents that new state. This is possible only if all state classes follow the same interface and the context itself works with these objects through that interface.</p>
<p>This structure may look similar to the Strategy pattern, but there is one key difference. In the State pattern, the particular states may be aware of each other and initiate transitions from one state to another, whereas strategies almost never know about each other.</p>
<h3 id="heading-real-world-analogy-1">Real-World Analogy</h3>
<p>The buttons and switches in your smartphone behave differently depending on the current state of the device.</p>
<ul>
<li><p>When the iPhone is unlocked, pressing buttons leads to executing various functions.</p>
</li>
<li><p>When the iPhone is locked, pressing any button leads to the unlock screen.</p>
</li>
<li><p>When the iPhone’s charge is low, pressing any button shows the charging screen.</p>
</li>
</ul>
<h3 id="heading-example-1">Example</h3>
<p>First of all, we can see the UML class diagram of what the implementation would be like without using the State design pattern and the problems that it tries to solve.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727089114385/044b7f01-4363-4446-9bcd-c5ec58905d7e.webp" alt class="image--center mx-auto" /></p>
<p>In this diagram, we can see that we have a <code>Context</code> class, which corresponds to the object that has different behaviors depending on the state it is in. These states can be modeled through an <code>Enum</code> class where we would have different possible states, as an example we would have two different states: <code>StateA</code> and <code>StateB</code>.</p>
<p>The <code>request</code> method of the <code>Context</code> class is where the open-closed principle is breaking since this method implements functionality based on the state the Context object is in. In addition to this, this method receives as a parameter a type of operation that adds conditional complexity to our problem. Even if we were to extract the behaviors of each state to external functions, we would still break this principle since every time we wanted to include a new state we would have to access this method and modify it.</p>
<p>Let’s see the implementation of this code to see it materialized in a programming language.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { State } <span class="hljs-keyword">from</span>  <span class="hljs-string">"./state.enum"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Context {

    <span class="hljs-keyword">private</span> state = State.stateA;

    request(operation: <span class="hljs-built_in">string</span>) {  
        <span class="hljs-keyword">switch</span> (<span class="hljs-built_in">this</span>.state){
            <span class="hljs-keyword">case</span> State.stateA:
                <span class="hljs-keyword">if</span>(operation === <span class="hljs-string">'request1'</span>){
                    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateA handles request1.'</span>); <span class="hljs-comment">//request1()</span>
                    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateA wants to change the state of the context.'</span>);
                    <span class="hljs-built_in">this</span>.state = State.stateB; <span class="hljs-comment">// Transition to another state</span>
                    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Context: Transition to concrete-state-B.`</span>);
                }<span class="hljs-keyword">else</span> {
                    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateA handles request2.'</span>); <span class="hljs-comment">// request2()</span>
                }
                <span class="hljs-keyword">break</span>
            <span class="hljs-keyword">case</span> State.stateB:
                <span class="hljs-keyword">if</span>(operation === <span class="hljs-string">'request1'</span>){
                    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateB handles request1.'</span>); <span class="hljs-comment">//request1()</span>
                }<span class="hljs-keyword">else</span>{
                    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateB handles request2.'</span>); <span class="hljs-comment">//request2()</span>
                    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateB wants to change the state of the context.'</span>);
                    <span class="hljs-built_in">this</span>.state = State.stateA; <span class="hljs-comment">// Transition to another state</span>
                    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Context: Transition to concrete-state-A.`</span>);
                }
            <span class="hljs-keyword">default</span>: <span class="hljs-comment">// Do nothing.</span>
                <span class="hljs-keyword">break</span>
        }
    }
}
</code></pre>
<p>In this code, we can see in the <code>request</code> method how the <code>switch</code> control structure is implemented, which couples the code to the <code>Context</code> states. Observe that the state change is done in this method itself, when we change the state we are changing the future behavior of this method since the code corresponding to the new state will be accessed.</p>
<p>The client code that would make use of this code is to implement the following.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Context } <span class="hljs-keyword">from</span> <span class="hljs-string">"./context"</span>;

<span class="hljs-keyword">const</span> context = <span class="hljs-keyword">new</span> Context();
context.request(<span class="hljs-string">'request1'</span>);
context.request(<span class="hljs-string">'request2'</span>);t
</code></pre>
<p>You can see that we simply instantiate an object of type Context and call the request method with different parameters. Obviously, although the result of this code is what we expect, we have all the design problems that we have mentioned above.</p>
<p>Now we are going to focus on solving this problem by applying the State pattern. Let’s start by looking at the class diagram.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727089258633/cc76feeb-6905-4a94-8200-d5b04926ecd4.webp" alt class="image--center mx-auto" /></p>
<p>The <code>Context</code> class is now related by composition to a new object that is the <code>State</code> of the context. The <code>Context</code> will still have methods associated with the functionality it performed previously, such as <code>request1</code> and <code>request2</code>. Also, a new method called <code>transitionTo</code> is added that will transition between the different states. That is, the change from one state to another will be done through a method that encapsulates this logic.</p>
<p>The <code>Context</code> class is related to an abstract class called <code>State</code>, which defines the contract that all possible states of our context must fulfill. In this specific case, two abstract methods <code>handle1</code> and <code>handle2</code> are defined, which will be specified in the concrete implementations of each of the states. That is, we are delegating the responsibility of implementing the behavior of each state to a specific subclass of said state.</p>
<p>On the other hand, the state class incorporates a reference to the context to be able to communicate with it to indicate that it must change its state. This reference in many implementations of the pattern does not exist, since the context reference is sent as a parameter to the methods defined in the state. We have preferred this implementation, which still respects the concept of composition and will greatly simplify the code we are showing.</p>
<p>Once we have seen the UML class diagram, we are going to see what the implementation of this design pattern would look like.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { State } <span class="hljs-keyword">from</span> <span class="hljs-string">"./state"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Context {
    <span class="hljs-keyword">private</span> state: State;

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">state: State</span>) {
        <span class="hljs-built_in">this</span>.transitionTo(state);
    }

    <span class="hljs-keyword">public</span> transitionTo(state: State): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Context: Transition to <span class="hljs-subst">${state.constructor.name}</span>.`</span>);
        <span class="hljs-built_in">this</span>.state = state;
        <span class="hljs-built_in">this</span>.state.setContext(<span class="hljs-built_in">this</span>);
    }

    <span class="hljs-keyword">public</span> request1(): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">this</span>.state.handle1();
    }

    <span class="hljs-keyword">public</span> request2(): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">this</span>.state.handle2();
    }
}
</code></pre>
<p>We start by looking at the <code>Context</code> class, and the first thing we can notice is that the state attribute is an object of the <code>State</code> class, rather than an <code>Enum</code>class. This <code>State</code> class is <code>abstract</code> so that responsibility can be delegated to concrete states. If we look at the <code>request1</code> and <code>request2</code> methods we see that they are making use of the <code>state</code> object and delegating responsibility to this class.</p>
<p>On the other hand, we have the implementation of the <code>transitionTo</code> method which we are going to use simply to change the <code>state</code> in which the <code>Context</code> is, and as we have already said to make it easier for us not to propagate the context through the handles of the state object, we are going to call the <code>setContext</code> method to assign the context to the <code>state</code>, making the communication between <code>state</code> and <code>context</code> permanent rather than through references between the methods.</p>
<p>The next step is to define the part corresponding to the states. First, we see that the <code>State</code> abstract class simply defines the abstract methods that the concrete states will implement and a reference to the <code>context</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Context } <span class="hljs-keyword">from</span> <span class="hljs-string">"./context"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> State {
    <span class="hljs-keyword">protected</span> context: Context;

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> handle1(): <span class="hljs-built_in">void</span>;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> handle2(): <span class="hljs-built_in">void</span>;
}
</code></pre>
<p>The concrete states are those that encapsulate the business logic corresponding to each of the states when the context object is in them. If we see the code associated with these classes, we can see how the <code>ConcreteStateA</code> and <code>ConcreteStateB</code> classes implement the <code>handle1</code> and <code>handle2</code> methods corresponding to the <code>State</code> interface, and how in our specific case we are transitioning from <code>StateA</code> to <code>StateB</code> when <code>handle1</code> is executed when the context is in the <code>StateA</code> . Whereas, we transition from <code>StateB</code> to <code>StateA</code> when <code>handle2</code> is executed when the <code>context</code>is in the <code>StateB</code>.</p>
<p>In any case, this is just an example of transitions between states, but it is important that you note that the states know each other, and that is a differentiating element of this design pattern compared to others such as the strategy pattern, in which the strategies do not know each other.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ConcreteStateB } <span class="hljs-keyword">from</span> <span class="hljs-string">"./concrete-state-B"</span>;
<span class="hljs-keyword">import</span> { State } <span class="hljs-keyword">from</span> <span class="hljs-string">"./state"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ConcreteStateA <span class="hljs-keyword">extends</span> State {
    <span class="hljs-keyword">public</span> handle1(): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateA handles request1.'</span>);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateA wants to change the state of the context.'</span>);
        <span class="hljs-built_in">this</span>.context.transitionTo(<span class="hljs-keyword">new</span> ConcreteStateB());
    }

    <span class="hljs-keyword">public</span> handle2(): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateA handles request2.'</span>);
    }
}

<span class="hljs-comment">/*****/</span>
<span class="hljs-keyword">import</span> { ConcreteStateA } <span class="hljs-keyword">from</span> <span class="hljs-string">"./concrete-state-A"</span>;
<span class="hljs-keyword">import</span> { State } <span class="hljs-keyword">from</span> <span class="hljs-string">"./state"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ConcreteStateB <span class="hljs-keyword">extends</span> State {
    <span class="hljs-keyword">public</span> handle1(): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateB handles request1.'</span>);
    }

    <span class="hljs-keyword">public</span> handle2(): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateB handles request2.'</span>);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'ConcreteStateB wants to change the state of the context.'</span>);
        <span class="hljs-built_in">this</span>.context.transitionTo(<span class="hljs-keyword">new</span> ConcreteStateA());
    }
}
</code></pre>
<p>To conclude, we see the client class that makes use of the design pattern.</p>
<p>The code is almost the same as the one we had without applying the pattern except that now we are creating an initial state with which the context will be initialized.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { ConcreteStateA } <span class="hljs-keyword">from</span> <span class="hljs-string">"./concrete-state-A"</span>;
<span class="hljs-keyword">import</span> { Context } <span class="hljs-keyword">from</span> <span class="hljs-string">"./context"</span>;

<span class="hljs-keyword">const</span> context = <span class="hljs-keyword">new</span> Context(<span class="hljs-keyword">new</span> ConcreteStateA()); <span class="hljs-comment">// Initial State</span>
context.request1();
context.request2();
</code></pre>
<p><a target="_blank" href="https://maxim-gorin.medium.com/stop-writing-if-else-trees-use-the-state-pattern-instead-1fe9ff39a39c">https://maxim-gorin.medium.com/stop-writing-if-else-trees-use-the-state-pattern-instead-1fe9ff39a39c</a></p>
<h2 id="heading-the-strategy-pattern">The Strategy Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727089518423/42452bbf-42a4-428c-90b3-ea4f832dfe8b.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Strategy</strong> is a behavioral design pattern that lets you define a family of algorithms, put each of them into a seperate class, and make their objects interchangeable.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/strategy">https://refactoring.guru/design-patterns/strategy</a></p>
</blockquote>
<h3 id="heading-problem-2">Problem</h3>
<p>One day you decided to create a navigation app for casual travelers. The app was centered around a beautiful map which helped users quickly orient themselves in the city.</p>
<p>One of the most important features of the app was automatic route planning. A user should be able to enter an address and see the fastest route to that destination displayed on the map.</p>
<p>The first version of the app could only build the routes over roads. People who traveled by car were bursting with joy. But apparently, not everybody likes to drive on their vacation. So with the next update, you add an option to build walking routes. Right after that, you added another option to let people use public transport on their routes.</p>
<p>However, that was only the beginning. Later you planned to add route building for cyclists. Or even later, another option for building routes through all of a city’s tourist attractions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727179080075/149f025d-7d16-497b-a6ce-81f47fc88af1.png" alt class="image--center mx-auto" /></p>
<p>While the app was successful from a business perspective, the technical part caused you headaches. Each time you add a new route algorithm, the main class of navigator doubles in size. At some point, the beast became too hard to maintain.</p>
<p>Any change to one of the algorithms, whether it was a simple bug fix or a slight adjustment of the street score, affected the whole class, increasing the chance of creating an error in the already working code.</p>
<p>In addition, teamwork became inefficient. Your teammates, who had been hired right after the successful release, complain that they spend too much time resolving merge conflicts. Implementing a new feature requires you to change the same huge class, conflicting with the code produced by other people.</p>
<h3 id="heading-solution-2">Solution</h3>
<p>The Strategy pattern suggests that you take a class that does something specific in a lot of different ways and extract all of these algorithms into separate classes called strategies.</p>
<p>The original class, called context, must have a field for storing a reference to one of the strategies. The context delegates the work to a link strategy object instead of executing it on its own.</p>
<p>The context isn’t responsible for selecting an appropriate algorithm for the job. Instead, the client passes the desired strategy to the context. In fact, the context doesn't know much about strategies. It works with all strategies through the same generic interface, which only exposes a single method for triggering the algorithm encapsulated within the selected strategy.</p>
<p>This way the context becomes independent of concrete strategies, so you can add new algorithms or modify existing ones without changing the code of the context or other strategies.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727180617034/dc44b1da-0b1a-4741-92bf-b91e7171f207.png" alt class="image--center mx-auto" /></p>
<p>In our navigation app, each routing algorithm can be extracted to its own class with a single <code>buildRoute</code> method. The method accepts an origin and destination and returns a collection of the route’s checkpoints.</p>
<p>Even though given the same arguments, each routing class might build a different route, the main navigator doesn't really care which algorithm is selected since its primary job is to render a set of checkpoints on the map. The class has a method for switching the active routing strategy, so its client, such as the buttons in the user interface, can replace the currently selected routing behavior with another one.</p>
<h3 id="heading-real-world-analogy-2">Real-World Analogy</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727181485437/f0b3c087-df3f-431a-b43f-b5093eff4218.png" alt class="image--center mx-auto" /></p>
<p>Imagine you have to get to the airport. You can catch a bus, order a cab, or get on your bicycle. These are your transportation strategies. You can pick one of the strategies depending on factors such as budget or time constraints.</p>
<h3 id="heading-example-2">Example</h3>
<p>Let’s say we have an app, that we want to secure ie add authentication to it. We have different auth schemes and strategies:</p>
<ul>
<li><p>Basic</p>
</li>
<li><p>Digest</p>
</li>
<li><p>OpenID</p>
</li>
<li><p>OAuth</p>
</li>
</ul>
<p>We might try to implement something like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> BasicAuth {}
<span class="hljs-keyword">class</span> DigestAuth {}
<span class="hljs-keyword">class</span> OpenIDAuth {}
<span class="hljs-keyword">class</span> OAuth {}
<span class="hljs-keyword">class</span> AuthProgram {
    runProgram(authStrategy:<span class="hljs-built_in">any</span>, ...) {
        <span class="hljs-built_in">this</span>.authenticate(authStrategy)
        <span class="hljs-comment">// ...</span>
    }
    authenticate(authStrategy:<span class="hljs-built_in">any</span>) {
        <span class="hljs-keyword">switch</span>(authStrategy) {
            <span class="hljs-keyword">if</span>(authStrategy == <span class="hljs-string">"basic"</span>)
                useBasic()
            <span class="hljs-keyword">if</span>(authStrategy == <span class="hljs-string">"digest"</span>)
                useDigest()
            <span class="hljs-keyword">if</span>(authStrategy == <span class="hljs-string">"openid"</span>)
                useOpenID()
            <span class="hljs-keyword">if</span>(authStrategy == <span class="hljs-string">"oauth"</span>)
                useOAuth()
        }
    }
}
</code></pre>
<p>The same old long chain of conditionals. Also, if we want to auth for a particular route in our program, we will find ourselves with the same thing.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> AuthProgram {
    route(path:<span class="hljs-built_in">string</span>, authStyle: <span class="hljs-built_in">any</span>) {
        <span class="hljs-built_in">this</span>.authenticate(authStyle)
        <span class="hljs-comment">// ...</span>
    }
}
</code></pre>
<p>if we apply the strategy design pattern here, we will create an interface that all auth strategies must implement:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> AuthStrategy {
    auth(): <span class="hljs-built_in">void</span>;
}
<span class="hljs-keyword">class</span> Auth0 <span class="hljs-keyword">implements</span> AuthStrategy {
    auth() {
        log(<span class="hljs-string">'Authenticating using Auth0 Strategy'</span>)
    }
}
<span class="hljs-keyword">class</span> Basic <span class="hljs-keyword">implements</span> AuthStrategy {
    auth() {
        log(<span class="hljs-string">'Authenticating using Basic Strategy'</span>)
    }
}
<span class="hljs-keyword">class</span> OpenID <span class="hljs-keyword">implements</span> AuthStrategy {
    auth() {
        log(<span class="hljs-string">'Authenticating using OpenID Strategy'</span>)
    }
}
</code></pre>
<p>The AuthStrategy defines the template on which all strategies must be built. Any concrete authentication strategy must implement the authentication method to provide us with its own style. We have the Auth0, Basic, and OpenID concrete strategies.</p>
<p>Next, we need to touch our AuthProgram class:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ...</span>
<span class="hljs-keyword">class</span> AuthProgram {
    <span class="hljs-keyword">private</span> _strategy: AuthStrategy
    use(strategy: AuthStrategy) {
        <span class="hljs-built_in">this</span>._strategy = strategy
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>
    }
    authenticate() {
        <span class="hljs-keyword">if</span>(<span class="hljs-built_in">this</span>._strategy == <span class="hljs-literal">null</span>) {
            log(<span class="hljs-string">"No Authentication Strategy set."</span>)
        }
        <span class="hljs-built_in">this</span>._strategy.auth()
    }
    route(path: <span class="hljs-built_in">string</span>, strategy: AuthStrategy) {
        <span class="hljs-built_in">this</span>._strategy = strategy
        <span class="hljs-built_in">this</span>.authenticate()
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>
    }
}
</code></pre>
<p>You see now, the authenticate method doesn’t carry the long switch case. The use method sets the authentication strategy to use and the authenticate method just calls the auth method. It could care less about how the AuthStrategy implements its authentication.</p>
<pre><code class="lang-typescript">log(<span class="hljs-keyword">new</span> AuthProgram().use(<span class="hljs-keyword">new</span> OpenID()).authenticate())
<span class="hljs-comment">// Authenticating using OpenID Strategy</span>
</code></pre>
<h2 id="heading-the-template-method-pattern">The Template Method Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727182881224/84b47c29-54df-4e79-bd17-e417c4122317.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Template Method</strong> is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.</p>
</blockquote>
<h3 id="heading-problem-3">Problem</h3>
<p>Imagine you are creating a data mining application that analyzes corporate documents. Users feed the app documents in various formats (PDF, DOC, CSV), and it tries to extract meaningful data from these docs in a uniform format.</p>
<p>The first version of the app could work only with DOC files. In the following version, it was able to support CSV files. A month later, you “taught” it to extract data from PDF files.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727340600404/4bf6d32b-2ea5-4971-a19a-c9d7e98a17ac.png" alt class="image--center mx-auto" /></p>
<p>At some point, you noticed that all three classes have a lot of similar code. While the code for dealing with various data formats was entirely different in all classes, the code for data processing and analysis is almost identical. Wouldn’t it be great to get rid of the code duplication, leaving the algorithm structure intact?</p>
<p>There was another problem related to the client code that used these classes. It had lots of conditionals that picked a proper course of action depending on the class of the processing object. If all three processing classes had a common interface or a base class, you would be able to eliminate the conditionals in the client code and use polymorphism when calling methods on a processing object.</p>
<h3 id="heading-solution-3">Solution</h3>
<p>The Template Method pattern suggests that you break down an algorithm into a series of steps, turn these steps into methods, and put a series of calls to these methods inside a single template method. The steps may either be <code>abstract</code> , or have some default implementation. To use the algorithm, the client is supposed to provide its own subclasses, implement all abstract steps, and override some of the optional ones if needed (but not the template method itself).</p>
<p>Let’s see how this will play out in our data mining app. We can create a base class for all three parsing algorithms. This class defines a template method consisting of a series of calls to various document-processing steps.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727341816419/6d24e499-61ea-48d6-a2d4-3d752a77f4d9.png" alt class="image--center mx-auto" /></p>
<p>First, we can declare all the steps <code>abstract</code> , forcing the subclasses to provide their own implementations for these methods. In our case, subclasses already have all the necessary implementations, so the only thing we might need to do is adjust the signatures of the methods to math the method of the subclass.</p>
<p>Now, let’s see what we can to do get rid of the duplication code. It looks like the code for opening/closing files and extracting/parsing data is different for various data formats, so there is no point in touching these methods. However, the implementation of other steps, such as analyzing the raw data and composing reports, is very similar, so it can be pulled up into the base class, where subclasses can share that code.</p>
<p>As you can see, we have two types of steps:</p>
<ul>
<li><p>abstract steps must be implemented by every subclass</p>
</li>
<li><p>optional steps already have some default implementation but can still be overridden if needed.</p>
</li>
</ul>
<h3 id="heading-real-world-analogy-3">Real-World Analogy</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727515365360/45826d73-5a4f-4126-ad68-718dc9f174b6.png" alt class="image--center mx-auto" /></p>
<p>The template method approach can be used in mass housing construction. The architectural plan for building a standard house may contain several extension points that would let a potential owner adjust some details of the resulting house.</p>
<p>Each building step, such as laying the foundation, framing, building walls, installing plumbing and wiring for water and electricity, etc, can be slightly changed to make the resulting house a little bit different from others.</p>
<h3 id="heading-example-3">Example</h3>
<p>In this example, we will explore how the Template method pattern can be applied to baking cakes, with different types of cake (e.g., Chocolate cake and Vanilla Cake) following a common baking process. We will see how this pattern promotes code reuse and flexibility by adhering to a consistent template.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727601239767/7b0b4789-c442-4530-9ba5-1192d3fe98b3.webp" alt class="image--center mx-auto" /></p>
<p><strong>Implementation</strong></p>
<ul>
<li><p><strong>Define the Abstract class</strong>: Create an abstract class that outlines the template method, which defines the sequence of steps. In our case, <code>Cake</code> is an abstract class with a <code>bakeCake()</code> the method that defines the steps to bake a cake.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> Cake {
    <span class="hljs-built_in">void</span> prepareIngredients();
    <span class="hljs-built_in">void</span> bake();
    <span class="hljs-built_in">void</span> cool();
    <span class="hljs-built_in">void</span> decorate();

    <span class="hljs-comment">// Template method</span>
    <span class="hljs-built_in">void</span> bakeCake() {
      prepareIngredients();
      bake();
      cool();
      decorate();
    }
  }
</code></pre>
</li>
<li><p><strong>Implement Concrete Subclasses</strong>: Create concrete subclasses that implement the specific steps defined in the abstract class. Each subclass customizes the process for a particular type of cake, such as <code>ChocolateCake</code> and <code>VanillaCake</code>.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">class</span> ChocolateCake <span class="hljs-keyword">extends</span> Cake {
    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> prepareIngredients() {
      print(<span class="hljs-string">"Preparing chocolate cake ingredients..."</span>);
    }

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> bake() {
      print(<span class="hljs-string">"Baking chocolate cake..."</span>);
    }

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> cool() {
      print(<span class="hljs-string">"Cooling chocolate cake..."</span>);
    }

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> decorate() {
      print(<span class="hljs-string">"Decorating chocolate cake..."</span>);
    }
  }

  <span class="hljs-keyword">class</span> VanillaCake <span class="hljs-keyword">extends</span> Cake {
    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> prepareIngredients() {
      print(<span class="hljs-string">"Preparing vanilla cake ingredients..."</span>);
    }

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> bake() {
      print(<span class="hljs-string">"Baking vanilla cake..."</span>);
    }

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> cool() {
      print(<span class="hljs-string">"Cooling vanilla cake..."</span>);
    }

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> decorate() {
      print(<span class="hljs-string">"Decorating vanilla cake..."</span>);
    }
  }
</code></pre>
</li>
</ul>
<p><strong>Usage</strong></p>
<ul>
<li><p><strong>Instantiate Concrete Cake Classes</strong>: Create instances of the <code>ChocolateCake</code> and <code>VanillaCake</code> classes, each following the template defined in the abstract <code>Cake</code> class.</p>
</li>
<li><p><strong>Execute the Template Method</strong>: Call the <code>bakeCake()</code> method on each cake instance. This method executes the entire baking process in a predefined sequence, with custom implementations for each cake.</p>
</li>
<li><p><strong>Observe the Steps</strong>: The steps of preparing ingredients, mixing, baking, cooling, and optionally adding toppings are executed in the order defined by the template method. Each step is customized based on the type of cake being baked.</p>
<pre><code class="lang-typescript">  <span class="hljs-built_in">void</span> main() {
    <span class="hljs-keyword">var</span> chocolateCake = ChocolateCake();
    <span class="hljs-keyword">var</span> vanillaCake = VanillaCake();

    <span class="hljs-comment">// Bake a chocolate cake</span>
    print(<span class="hljs-string">"\nBaking a Chocolate Cake:"</span>);
    chocolateCake.bakeCake();

    <span class="hljs-comment">// Bake a vanilla cake</span>
    print(<span class="hljs-string">"\nBaking a Vanilla Cake:"</span>);
    vanillaCake.bakeCake();
  }
</code></pre>
</li>
</ul>
<h2 id="heading-the-visitor-pattern">The Visitor Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727602757364/136d26ec-09a4-45f6-8d3b-d8e6b3852f27.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Visitor is a behavioral design pattern that lets separate algorithms from the objects on which they operate</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/visitor">https://refactoring.guru/design-patterns/visitor</a></p>
</blockquote>
<h3 id="heading-problem-4">Problem</h3>
<p>Imagine that your team develops an app that works with geographic information structured as one colossal graph. Each node of the graph may represent a complex entity such as a city, but also more granular things like industries, sightseeing areas, etc. The nodes are connected with others if there is a road between the real objects that they represent. Under the hood, each node type is represented by its own class, while each specific node is an object.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727604699695/34e091ff-44bc-48a3-9e97-bd852a08afb8.png" alt class="image--center mx-auto" /></p>
<p>At some point, you have a task to implement exporting the graph into XML format. At first, the job seemed pretty straightforward. You planned to add an export method to each node class and the leverage recursion to go over each node of the graph, executing the export method. The solution was simple and elegant: thanks to polymorphism, you weren’t coupling the code that called the export method to concrete classes of nodes.</p>
<p>Unfortunately, the system architect refused to allow you to alter existing node classes. He said that the code was already in production and he didn’t want to risk breaking it because of potential bugs in your changes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727605303776/77db58a8-e7cd-4dac-a933-175559512715.png" alt class="image--center mx-auto" /></p>
<p>Besides, he questioned whether it makes sense to have the XML export code within the node classes. The primary of these classes was to work with geodata. The XML export behavior would look alien there.</p>
<p>There was another reason for the refusal. It was highly likely that after this feature was implemented, someone from the marketing department would ask you to provide the ability to export into a different format or request some other weird stuff. This would force you to change those precious and fragile classes again.</p>
<h3 id="heading-solution-4">Solution</h3>
<p>The Visitor pattern suggests that you place a new behavior into a separate class called visitor, instead of trying to integrate it into existing classes. The original object that had to perform the behavior is now passed to one of the visitor’s methods as an argument, providing the method access to all necessary data contained within the object.</p>
<p>Now, what if that behavior can be executed over objects of different classes? For example, in our case with XML export, the actual implementation would probably be a little bit different across node classes. Thus, the visitor class may define not one, but a set of methods, each of which could take arguments of different types, like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> ExportVisitor <span class="hljs-keyword">implements</span> Visitor is
    method doForCity(City c) { ... }
    method doForIndustry(Industry f) { ... }
    method doForSightSeeing(SightSeeing ss) { ... }
    <span class="hljs-comment">// ...</span>
</code></pre>
<p>But how exactly would we call these methods, especially when dealing with the whole graph? These methods have different signatures, so we can’t use polymorphism. To pick a proper visitor method that is able to process a given object, we would need to check its class. Doesn’t this sound like a nightmare?</p>
<pre><code class="lang-typescript">foreach (Node node <span class="hljs-keyword">in</span> graph)
    <span class="hljs-keyword">if</span> (node <span class="hljs-keyword">instanceof</span> City)
        exportVisitor.doForCity((City) node)
    <span class="hljs-keyword">if</span> (node <span class="hljs-keyword">instanceof</span> Industry)
        exportVisitor.doForIndustry((Industry) node)
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>You might ask, why don’t we use method overloading? That is when you give all methods the same name, even if they support different sets of parameters. Unfortunately, even assuming that our programming language supports it at all (as Java and C# do) won’t help us since the exact class of the node object is known in advance, the overloading mechanism won’t be able to determine a method to execute. It will default to the method that takes an object of the base <code>Node</code> class.</p>
<p>However, the Visitor pattern addresses this problem. It uses a technique called <strong>Double Dispatch,</strong> which helps to execute the proper method on an object without cumbersome conditionals. Instead of letting the client select the proper version of the method to call, how about we delegate this choice to objects we are passing to the visitor as an argument? Since the object knows its own classes, it will be able to pick a proper method for the visitor less awkwardly. They “accept“ a visitor and tell it what visiting method should be executed.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Client code</span>
foreach (Node node <span class="hljs-keyword">in</span> graph)
    node.accept(exportVisitor)

<span class="hljs-comment">// City</span>
<span class="hljs-keyword">class</span> City is
    method accept(Visitor v) is
        v.doForCity(<span class="hljs-built_in">this</span>)
    <span class="hljs-comment">// ...</span>

<span class="hljs-comment">// Industry</span>
<span class="hljs-keyword">class</span> Industry is
    method accept(Visitor v) is
        v.doForIndustry(<span class="hljs-built_in">this</span>)
    <span class="hljs-comment">// ...</span>
</code></pre>
<p>I confess. We had to change to node classes after all. But at least the change is trivial and it lets us add further behaviors without altering the code once again.</p>
<p>Now, if we extract a common interface for all visitors, all existing nodes can work with any visitor you introduce to the app. If you find yourself introducing a new behavior related to nodes, all you have to do is implement a new visitor class.</p>
<h3 id="heading-real-world-analogy-4">Real-World Analogy</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727686815022/d844de1f-ec40-49a1-a424-295521b3a812.png" alt class="image--center mx-auto" /></p>
<p>Imagine a seasoned insurance agent who is eager to get new customers. He can visit any building in a neighborhood, trying to sell insurance to everyone he meets. Depending on the type of organization that occupies the building, he can offer specialized insurance policies:</p>
<ul>
<li><p>If it’s a residential building, he sells medical insurance.</p>
</li>
<li><p>if it’s a bank, he sells theft insurance.</p>
</li>
<li><p>if it’s a coffee shop, he sells fire and flood insurance.</p>
</li>
</ul>
<h3 id="heading-example-4">Example</h3>
<p>Let’s try to describe a simple real-life example (you can play with it - see <a target="_blank" href="https://github.com/JonnyFox/typescript-design-patterns/blob/master/src/patterns/behavioral/visitor.ts">this Github repo</a> written using <a target="_blank" href="https://www.typescriptlang.org/">Typescript</a>) where we have a list of <code>Employee</code> and <code>Clerk</code> objects on which we need to perform two actions (and maybe others in the future):</p>
<ul>
<li><p><strong>increase income</strong>: increase the income of the Employee/Clerk by 30% and 10% respectively.</p>
</li>
<li><p><strong>increase vacation days</strong>: increase the vacation by 3 days for the <code>Employee</code> and by 1 day for the <code>Clerk</code></p>
</li>
</ul>
<p>First, we declare the <code>IVisitor</code> interface that exposes the visit method: This method will be suitably defined by the two visitor implementations regarding the actions above, ie. <code>IncomeVisitor</code> and <code>VacationVisitor</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> IVisitor {
    visit(item: Employee);
}

<span class="hljs-keyword">class</span> IncomeVisitor <span class="hljs-keyword">implements</span> IVisitor {
    visit(item: Employee) {
        <span class="hljs-keyword">if</span> (item <span class="hljs-keyword">instanceof</span> Clerk) {
            item.income *= <span class="hljs-number">1.1</span>;
        } <span class="hljs-keyword">else</span> { 
            item.income *= <span class="hljs-number">1.3</span>;
        }
    }
}

<span class="hljs-keyword">class</span> VacationVisitor <span class="hljs-keyword">implements</span> IVisitor {
    visit(item: Employee) {
        <span class="hljs-keyword">if</span> (item <span class="hljs-keyword">instanceof</span> Clerk) {
            item.vactionDays += <span class="hljs-number">1</span>;
        } <span class="hljs-keyword">else</span> {
            item.vactionDays += <span class="hljs-number">3</span>;
        }
    }
}
</code></pre>
<p>In this case, we distinguish the type <code>Clerk</code> from the type <code>Employee</code> with a simple <code>if(item instanceof MyType)</code> doing the operations according to the above specifications: notice this is a simplified variation of the visitor pattern that can (or should) provide separate methods for different types, see a second implementation <a target="_blank" href="https://github.com/JonnyFox/typescript-design-patterns/blob/master/src/patterns/behavioral/visitor2.ts">here</a>.</p>
<p>Let’s proceed by adding the second part of the pattern:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> IVisitable {
    accept(v: IVisitor);
}

<span class="hljs-keyword">class</span> Employee <span class="hljs-keyword">implements</span> IVisitable {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> name: <span class="hljs-built_in">string</span>,
        <span class="hljs-keyword">public</span> income: <span class="hljs-built_in">number</span> = 10000,
        <span class="hljs-keyword">public</span> vactionDays: <span class="hljs-built_in">number</span> = 30,
    </span>) { }

    <span class="hljs-keyword">public</span> accept(v: IVisitor) {
        v.visit(<span class="hljs-built_in">this</span>);
    }
}

<span class="hljs-keyword">class</span> Clerk <span class="hljs-keyword">extends</span> Employee {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>) {
        <span class="hljs-built_in">super</span>(name);
    }
}

<span class="hljs-keyword">class</span> Employees <span class="hljs-keyword">implements</span> IVisitable {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> employees: Employee[] = []
    </span>) { }

    <span class="hljs-keyword">public</span> accept(v: IVisitor) {
        <span class="hljs-built_in">this</span>.employees.forEach(<span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> e.accept(v));
    }
}
</code></pre>
<p>We declare a new interface <code>IVisitable</code> that exposes the accept method: This method allows us to “receive“ a visitor instance and perform the action appropriately on the interested item.</p>
<p>This allows us to specify a different behavior for different types of objects/structures: In this case, if we specify that in the case of an Employee list, the accept method must be executed on each component on the list.</p>
<p>Here is a simple example that includes all the code seen so far:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> IVisitor {
    visit(item: Employee);
}

<span class="hljs-keyword">class</span> IncomeVisitor <span class="hljs-keyword">implements</span> IVisitor {
    visit(item: Employee) {
        <span class="hljs-keyword">if</span> (item <span class="hljs-keyword">instanceof</span> Clerk) {
            item.income *= <span class="hljs-number">1.1</span>;
        } <span class="hljs-keyword">else</span> { 
            item.income *= <span class="hljs-number">1.3</span>;
        }
    }
}

<span class="hljs-keyword">class</span> VacationVisitor <span class="hljs-keyword">implements</span> IVisitor {
    visit(item: Employee) {
        <span class="hljs-keyword">if</span> (item <span class="hljs-keyword">instanceof</span> Clerk) {
            item.vactionDays += <span class="hljs-number">1</span>;
        } <span class="hljs-keyword">else</span> {
            item.vactionDays += <span class="hljs-number">3</span>;
        }
    }
}

<span class="hljs-keyword">interface</span> IVisitable {
    accept(v: IVisitor);
}

<span class="hljs-keyword">class</span> Employee <span class="hljs-keyword">implements</span> IVisitable {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> name: <span class="hljs-built_in">string</span>,
        <span class="hljs-keyword">public</span> income: <span class="hljs-built_in">number</span> = 10000,
        <span class="hljs-keyword">public</span> vactionDays: <span class="hljs-built_in">number</span> = 30,
    </span>) { }

    <span class="hljs-keyword">public</span> accept(v: IVisitor) {
        v.visit(<span class="hljs-built_in">this</span>);
    }
}

<span class="hljs-keyword">class</span> Clerk <span class="hljs-keyword">extends</span> Employee {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>) {
        <span class="hljs-built_in">super</span>(name);
    }
}

<span class="hljs-keyword">class</span> Employees <span class="hljs-keyword">implements</span> IVisitable {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> employees: Employee[] = []
    </span>) { }

    <span class="hljs-keyword">public</span> accept(v: IVisitor) {
        <span class="hljs-built_in">this</span>.employees.forEach(<span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> e.accept(v));
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> VisitorPattern {
    <span class="hljs-keyword">public</span> run(): <span class="hljs-built_in">void</span> {
        <span class="hljs-keyword">const</span> list = <span class="hljs-keyword">new</span> Employees([<span class="hljs-keyword">new</span> Clerk(<span class="hljs-string">'Alan'</span>), <span class="hljs-keyword">new</span> Employee(<span class="hljs-string">'Tim'</span>), <span class="hljs-keyword">new</span> Employee(<span class="hljs-string">'Zoe'</span>)]);

        list.accept(<span class="hljs-keyword">new</span> IncomeVisitor());
        list.accept(<span class="hljs-keyword">new</span> VacationVisitor());
    }
}
</code></pre>
<h1 id="heading-summary">Summary</h1>
<p>We have together explored 22 design patterns. So by now, we should have a clear understanding of what design pattern really is and what are the benefits of it. So in general, you won’t be able to copy the whole pattern code like the way you copy code from Stackoverflow because the design pattern is a general concept. The pattern is not a specific piece of code, but the general concept for solving a particular problem. You can follow design patterns and implement a solution that suits the reality of a real program.</p>
<p>So guys, we have already reached the end of this article, thank you for taking the time to read the whole series! I hope you found the information helpful and gained some valuable insights into this topic.</p>
<p>happy coding !!!!!!!!</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://betterprogramming.pub/understanding-the-observer-design-pattern-f621b1d0b6c9">https://betterprogramming.pub/understanding-the-observer-design-pattern-f621b1d0b6c9</a></p>
<p><a target="_blank" href="https://blog.bitsrc.io/understanding-the-state-design-pattern-7f40f6b5e29e">https://blog.bitsrc.io/understanding-the-state-design-pattern-7f40f6b5e29e</a></p>
<p><a target="_blank" href="https://blog.bitsrc.io/keep-it-simple-with-the-strategy-design-pattern-c36a14c985e9">https://blog.bitsrc.io/keep-it-simple-with-the-strategy-design-pattern-c36a14c985e9</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/template-method-design-pattern-explained-e16c6e5e20f8">https://levelup.gitconnected.com/template-method-design-pattern-explained-e16c6e5e20f8</a></p>
<p><a target="_blank" href="https://medium.com/factory-mind/visitor-design-pattern-demystified-940bd3903d56">https://medium.com/factory-mind/visitor-design-pattern-demystified-940bd3903d56</a></p>
]]></content:encoded></item><item><title><![CDATA[Design Patterns Handbook - Part III]]></title><description><![CDATA[In Part I and Part II, we’ve covered creational and structural design patterns. Today, we'll dive into the final topic in our Design Patterns series: Behavioral Design Patterns.
Let’s begin!
Behavioral Design Patterns
Behavioral Design Patterns are d...]]></description><link>https://blog.tuanhadev.tech/design-patterns-handbook-part-iii</link><guid isPermaLink="true">https://blog.tuanhadev.tech/design-patterns-handbook-part-iii</guid><category><![CDATA[Behavioral Design Pattern]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[Object Relationship]]></category><category><![CDATA[code organization]]></category><category><![CDATA[code maintainability]]></category><category><![CDATA[Scalable web applications]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Sat, 31 Aug 2024 12:02:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Pwl2LxZoTAE/upload/a3e41fb5733c472f246ff765297659cf.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In <a target="_blank" href="https://blog.tuanhadev.tech/design-patterns-handbook-part-i">Part I</a> and <a target="_blank" href="https://blog.tuanhadev.tech/design-patterns-handbook-part-ii">Part II</a>, we’ve covered creational and structural design patterns. Today, we'll dive into the final topic in our Design Patterns series: <strong>Behavioral Design Patterns</strong>.</p>
<p>Let’s begin!</p>
<h1 id="heading-behavioral-design-patterns">Behavioral Design Patterns</h1>
<p>Behavioral Design Patterns are design patterns that focus on how objects interact and communicate with each other to fulfill certain responsibilities. These patterns provide solutions to common problems arising in the interaction between objects and help achieve better communication, collaboration, and flexibility between objects.</p>
<p>There are several types of Behavioral Design Patterns, including:</p>
<ol>
<li><p><strong>Chain of Responsibility</strong></p>
</li>
<li><p><strong>Command</strong></p>
</li>
<li><p><strong>Iterator</strong></p>
</li>
<li><p><strong>Mediator</strong></p>
</li>
<li><p><strong>Memento</strong></p>
</li>
<li><p><strong>Observe</strong></p>
</li>
<li><p><strong>State</strong></p>
</li>
<li><p><strong>Strategy</strong></p>
</li>
<li><p><strong>Template Method</strong></p>
</li>
<li><p><strong>Visitor</strong></p>
</li>
</ol>
<h2 id="heading-the-chain-of-responsibility-pattern">The Chain of Responsibility Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724057306202/56e96836-cd37-46fa-ad5a-c63ceef32556.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Chain of Responsibility</strong> is a behavioral design pattern that lets you pass requests along the chain of handlers. Upon receiving the request, each handler either decides to process the request or to pass it to the next handler in the chain.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/chain-of-responsibility">https://refactoring.guru/design-patterns/chain-of-responsibility</a></p>
</blockquote>
<h3 id="heading-problem">Problem</h3>
<p>Imagine you are working on an online ordering system. You want to restrict access to the system so only authenticated users can create orders. Also, users who have administrative permissions must have full access to all orders.</p>
<p>After a bit of planning, you realize that these checks must be performed sequentially. The application can attempt to authenticate users to the system whenever it receives a request that contains the user's credentials. However, if those credentials aren't correct and authentication fails, there is no reason to proceed with any other checks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724058442042/fed1563d-58fe-40e6-8cc4-a256a9737366.png" alt class="image--center mx-auto" /></p>
<p>During the next few months, you implemented several of those sequential checks.</p>
<ul>
<li><p>One of your colleagues suggests that is unsafe to pass raw data straight to the ordering system. So you added an extra validation step to sanitize the data in a request.</p>
</li>
<li><p>Later, somebody noticed that the system was vulnerable to brute-force password cracking. To negate this, you promptly added a check that filters repeated failed requests coming from the same IP address.</p>
</li>
<li><p>Someone else suggested that you could speed up the system by returning cached results on repeated requests containing the same data. Hence, you added another check that lets the request pass through to the system only if there is no suitable cached response.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724060213276/bc42b479-d98d-4b90-91ec-aca53f3977b4.png" alt class="image--center mx-auto" /></p>
<p>The code of the checks, which had already looked like a mess, became more and more bloated as you added each new feature. Changing one check sometimes affected the others. Worst of all, when you tried to reuse the checks to protect other components of the system, you had to duplicate some of the code since those components required some of the checks, but not all of them.</p>
<p>The system became very hard to comprehend and expensive to maintain. You struggled with the code for a while, until one day you decided to refactor the whole thing.</p>
<h3 id="heading-solution">Solution</h3>
<p>Like many other behavioral design patterns, the <strong>Chain of Responsibility</strong> relies on transforming particular behaviors into stand-alone objects called <strong>handlers</strong>. In our case, each check should be extracted to its own class with a single method that performs a check. The request, along with its data, is passed to this method as an argument.</p>
<p>The pattern suggests that you link the handler into a chain. Each linked handler has a field for storing a reference to the next handler in the chain. In addition to processing the request, handlers pass the request further along the chain. The request travels along the chain until all handlers have had a chance to process it.</p>
<p>Here is the best part: a handler can decide not to pass the request further down the chain and effectively stop any further processing.</p>
<p>In our example with ordering systems, a handler performs the processing and then decides whether to pass the request further down the train. Assuming the request contains the right data, all the handlers can execute their primary behaviors, whether it's authentication check or caching.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724062346647/19622bb8-eb5e-48f9-8a8f-a37a83b2af37.png" alt class="image--center mx-auto" /></p>
<p>However, there is a slightly different approach (and it's a bit more canonical) in which, upon receiving the request, a handler decides whether it can process it. If it can, it doesn't pass the request any further. So it's either only one handler that processes the request or none at all. This approach is very common when dealing with events in stacks of elements within a graphical user interface.</p>
<p>For instance, when a user clicks on a button, the event propagates through the chain of GUI elements that starts with the button, goes along its containers (like forms and panels), and ends up with the main application window. The event is processed by the first element in the chain that's capable of handling it. This example is also noteworthy because it shows that a chain can always be extracted from an object tree.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724063052933/ef35f387-da1c-468e-ac58-48a7183c5206.png" alt class="image--center mx-auto" /></p>
<p>It's crucial that all handler classes implement the same interface. Each concrete handler should only care about the following one having the execute method. This way you can compose chains at runtime, using various handlers without coupling your code to their concrete classes.</p>
<h3 id="heading-chain-of-responsibility-pattern-advantages-and-disadvantages">Chain of Responsibility Pattern: Advantages and Disadvantages</h3>
<p>The Chain of Responsibility pattern has a number of advantages, summarized in the following points:</p>
<ul>
<li><p>The code is more maintainable because it is less coupled between the object and other the object handles a request. The object (sender) only needs to know that a request will be handled by the handlers. That is to say that both (the receiver and sender) have no explicit knowledge about each other. Besides, the object in the chain doesn't need to know about the chain's structure.</p>
</li>
<li><p>Clean code. The <em>Open-Closed Principle (OCP)</em> is guaranteed since the new handler can be introduced without breaking existing code in the chain.</p>
</li>
<li><p>Cleaner code. The <em>Single Responsibility Principle (SRP)</em> is respected since the responsibility of each handler is transferred into its into <code>handle</code> method instead of having that business logic in the client code.</p>
</li>
</ul>
<p>A well-known drawback of this pattern is that the <em>receipt isn’t guaranteed</em>. That’s due to the fact that the request has no explicit receiver. Therefore, the request can fall off the end of the chain without ever being handled.</p>
<p>Finally, the main drawback of the chain of responsibility pattern — like most design patterns — is that there’s an increase in code complexity and the number of classes required for the code. With that said, this disadvantage is well known when applying design patterns — it’s the price to pay for gaining abstraction in the code.</p>
<h3 id="heading-example-in-typescript">Example in Typescript</h3>
<p>In this example, we are going to use the chain of responsibility pattern to simulate an authentication and authorization system using a set of middleware that applies checks on a request.</p>
<p>As we did in the previous example, let’s start by taking a look at the UML diagram that is going to help us identify each of the parts that this pattern is composed of.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724065313984/d02efc44-5391-4d5b-beb2-dbe37d7e5cc4.png" alt class="image--center mx-auto" /></p>
<p>Notice that our class diagram incorporates some extra classes. These give context to our problem, but the chain of responsibility pattern can easily be identified among the set of classes.</p>
<p>Before we address the implementation of our problem, let’s define a set of constants that will give us semantic value to these values. These three constants are quite simple: Firstly, we have two false users (<code>USERS</code>), secondly, the number of maximum authentication requests per minute (<code>REQUEST_PER_MINUTE</code>), and finally, the waiting time in milliseconds when the number of requests per minute is exceeded (<code>WAIT_TIME</code>).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> USERS = {
  <span class="hljs-attr">ADMIN</span>: {
    <span class="hljs-attr">email</span>: <span class="hljs-string">"admin@example.com"</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">"admin"</span>,
  },
  <span class="hljs-attr">USER</span>: {
    <span class="hljs-attr">email</span>: <span class="hljs-string">"user@example.com"</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">"user"</span>,
  },
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> REQUEST_PER_MINUTE = <span class="hljs-number">2</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> WAIT_TIME = <span class="hljs-number">60</span>_000;
</code></pre>
<p>We start to define the pattern again by defining the <code>Handler</code> interface with the same two methods as in the basic structure of the pattern. In other words, the <code>Handler</code> interface is made up of the <code>setNextMiddleware</code> and <code>execute</code> methods, the first being in charge of linking each of the middleware, and the second method is responsible for handling the request.</p>
<p>In our case, the request that we have to handle is the one composed by a <code>User</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">"./user.interface"</span>;

<span class="hljs-keyword">export</span> interface Handler {
  setNextMiddleware(handler: Handler): <span class="hljs-keyword">void</span>;

  execute(user: User): boolean;
}
</code></pre>
<p>The objects that behave as users must satisfy the <code>User</code> interface, which is simply composed of an <code>email</code> and a <code>password</code>. The goal of this tutorial is to understand the chain of responsibility pattern, so this part will be simple — but complete enough to solve the authentication and authorization problem.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> interface User {
  <span class="hljs-attr">email</span>: string;
  password: string;
}
</code></pre>
<p>Continuing with the pattern, the next element is the development of the abstract class, <code>Middleware</code>, that implements the <code>Handler</code> interface. In this implementation, there is the <code>setNextMiddleware</code> method, which allows linking the following middleware, and the <code>execute</code> method, which is <code>abstract</code> and is implemented in each of the specific middleware. Finally, we have the <code>checkNext</code> method that checks if we have reached the end of the middleware chain, responding <code>true</code> when all the checks have been passed. If there is a next middleware then the next middleware check will be executed.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Handler, User } <span class="hljs-keyword">from</span> <span class="hljs-string">"../interfaces"</span>;

<span class="hljs-keyword">export</span> abstract <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Middleware</span> <span class="hljs-title">implements</span> <span class="hljs-title">Handler</span> </span>{
  private next: Handler;

  public setNextMiddleware(next: Handler): Handler {
    <span class="hljs-built_in">this</span>.next = next;
    <span class="hljs-keyword">return</span> next;
  }
  public abstract execute(user: User): boolean;

  protected checkNext(user: User): boolean {
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.next) {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.next.execute(user);
  }
}
</code></pre>
<p>The first middleware we need to build for the authentication and authorization system is verification that the user exists.</p>
<p>In our example, we have modeled a fake server where we have two registered users (the same ones that we previously defined in the constants). This server, which we will see later, provides us an API with the <code>hasEmail</code> and <code>isValidPassword</code> methods. The <code>execute</code> method will receive the request (a <code>User</code>) and we would make the checks to ensure the user exists on the server. First, it checks if the email exists on the server; if so, the username and password are checked. If the check is passed, the <code>checkNext</code> method is executed, which consists of making the request to the next middleware.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Middleware } <span class="hljs-keyword">from</span> <span class="hljs-string">"./middleware"</span>;
<span class="hljs-keyword">import</span> { Server } <span class="hljs-keyword">from</span> <span class="hljs-string">"../server"</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">"../interfaces"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserExistsMiddleware</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Middleware</span> </span>{
  public <span class="hljs-keyword">constructor</span>(private server: Server) {
    <span class="hljs-built_in">super</span>();
  }

  public execute({ email, password }: User): boolean {
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.server.hasEmail(email)) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"This email is not registered!"</span>);
      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.server.isValidPassword(email, password)) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Wrong password!"</span>);
      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.checkNext({ email, password });
  }
}
</code></pre>
<p>The following middleware would be the one that allows us to control the number of requests per minute.</p>
<p>This is where you can see the Open-Close Principle (OCP) — it is very easy to incorporate new middleware and checks without breaking the existing code. You can also see the Single Responsibility Principle(SRP) since each middleware has only one responsibility.</p>
<p>In this middleware, we receive the maximum number of requests per minute as a parameter. In addition, this middleware has some private attributes that allow you to control the time that has passed between requests, and the number of attempts that have been made in one minute.</p>
<p>If you look at the logic of the execute method, it’s quite simple — but you can check how a check exists again. This is what stops the chain of responsibility since it’s resolved by this handler.</p>
<p>In case the check is passed, this middleware, like the previous one, will proceed to pass the request to the next middleware.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Middleware } <span class="hljs-keyword">from</span> <span class="hljs-string">"./middleware"</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">"../interfaces"</span>;
<span class="hljs-keyword">import</span> { WAIT_TIME } <span class="hljs-keyword">from</span> <span class="hljs-string">"../app.constants"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThrottlingMiddleware</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Middleware</span> </span>{
  private request: number = <span class="hljs-number">0</span>;
  private currentTime: number = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
  private requestPerMinute: number;

  <span class="hljs-keyword">constructor</span>(requestPerMinute: number) {
    <span class="hljs-built_in">super</span>();
    <span class="hljs-built_in">this</span>.requestPerMinute = requestPerMinute;
  }

  public execute(user: User): boolean {
    <span class="hljs-keyword">const</span> now = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
    <span class="hljs-keyword">const</span> limitTime = <span class="hljs-built_in">this</span>.currentTime + WAIT_TIME;

    <span class="hljs-keyword">if</span> (now &gt; limitTime) {
      <span class="hljs-built_in">this</span>.request = <span class="hljs-number">0</span>;
      <span class="hljs-built_in">this</span>.currentTime = now;
    }

    <span class="hljs-built_in">this</span>.request++;

    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.request &gt; <span class="hljs-built_in">this</span>.requestPerMinute) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Request limit exceeded!"</span>);
      <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.checkNext(user);
  }
}
</code></pre>
<p>Finally, the following middleware is in charge of checking if the user is an administrator or not, obviously, this should have been done with a real check on a knowledge base. However, to illustrate that each middleware can have different parameters, a basic check has been performed.</p>
<p>In the case of being an admin, the chain of responsibility is finished. Otherwise, it continues. This is so that when a new middleware is developed, it can be managed in the chain. In our case, here we end the responsibility chain because we do not have any more middleware implemented.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RoleMiddleware</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Middleware</span> </span>{
  public execute({ email, password }: User): boolean {
    <span class="hljs-keyword">if</span> (email === USERS.ADMIN.email) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello, admin!"</span>);
      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello, user!"</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.checkNext({ email, password });
  }
}
</code></pre>
<p>For educational purposes, we have built a <code>Server</code> class that stores users on a <code>Map&lt;String, User&gt;</code> and has a Middleware that is the one that begins the chain of responsibility.</p>
<p>The <code>register</code>, <code>hasEmail</code> and <code>isValidPassword</code> methods are focused on performing these operations using the users who are registered on the server.</p>
<p>The <code>logIn</code> method receives the request from the user. The chain of responsibility begins on line 13 with the execution of the middleware sending the user as a request.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Middleware } <span class="hljs-keyword">from</span> <span class="hljs-string">"./middlewares"</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">"./interfaces"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Server</span> </span>{
  private users: <span class="hljs-built_in">Map</span>&lt;string, User&gt; = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>&lt;string, User&gt;();
  private middleware: Middleware;

  public setMiddleware(middleware: Middleware): <span class="hljs-keyword">void</span> {
    <span class="hljs-built_in">this</span>.middleware = middleware;
  }

  public logIn(email: string, <span class="hljs-attr">password</span>: string): boolean {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.middleware.execute({ email, password })) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Authorization have been successful!"</span>);

      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
  }

  public register(email: string, <span class="hljs-attr">password</span>: string): <span class="hljs-keyword">void</span> {
    <span class="hljs-keyword">const</span> user: User = {
      email,
      password,
    };
    <span class="hljs-built_in">this</span>.users.set(email, user);
  }

  public hasEmail(email: string): boolean {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.users.has(email);
  }

  public isValidPassword(email: string, <span class="hljs-attr">password</span>: string): boolean {
    <span class="hljs-keyword">const</span> user = <span class="hljs-built_in">this</span>.users.get(email);
    <span class="hljs-keyword">return</span> user.password === password;
  }
}
</code></pre>
<p>Finally, the client that makes use of our middleware system is the one shown in the code. A server has been created and two user accounts registered (obviously this would be our real backend and should not have been done here).</p>
<p>Subsequently, the chain of responsibilities is indicated using the following middleware in the following order:</p>
<p>UserExists -&gt; Trottling -&gt; Role</p>
<p>Finally, we have created a loop in which email and password are requested.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {
  Middleware,
  RoleMiddleware,
  ThrottlingMiddleware,
  UserExistsMiddleware,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"./middlewares"</span>;
<span class="hljs-keyword">import</span> { REQUEST_PER_MINUTE, USERS } <span class="hljs-keyword">from</span> <span class="hljs-string">"./app.constants"</span>;

<span class="hljs-keyword">import</span> { Server } <span class="hljs-keyword">from</span> <span class="hljs-string">"./server"</span>;

<span class="hljs-keyword">const</span> readline = <span class="hljs-built_in">require</span>(<span class="hljs-string">"readline-sync"</span>);

<span class="hljs-keyword">const</span> server = <span class="hljs-keyword">new</span> Server();
server.register(USERS.ADMIN.email, USERS.ADMIN.password);
server.register(USERS.USER.email, USERS.USER.password);

<span class="hljs-keyword">const</span> middleware: Middleware = <span class="hljs-keyword">new</span> ThrottlingMiddleware(REQUEST_PER_MINUTE);
middleware
  .setNextMiddleware(<span class="hljs-keyword">new</span> UserExistsMiddleware(server))
  .setNextMiddleware(<span class="hljs-keyword">new</span> RoleMiddleware());

server.setMiddleware(middleware);

<span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
  <span class="hljs-keyword">let</span> success = <span class="hljs-literal">false</span>;

  <span class="hljs-keyword">do</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"....Autentication Software...."</span>);
    <span class="hljs-keyword">const</span> email = readline.question(<span class="hljs-string">"Email: "</span>);
    <span class="hljs-keyword">const</span> password = readline.question(<span class="hljs-string">"Password: "</span>, { <span class="hljs-attr">hideEchoBack</span>: <span class="hljs-literal">true</span> });
    success = server.logIn(email, password);
  } <span class="hljs-keyword">while</span> (!success);
}
</code></pre>
<p>To end this article we are going to see the code working and for this I have recorded several GIFs.</p>
<p>In the first, we can see the <code>UserExists</code> and <code>Throttling</code> middleware in operation. I have entered the wrong email and password several times, the first middleware (<code>Throttling</code>) will leave the responsibility the first two times to the <code>UserExists</code> middleware, which rejects the validation of the user/password. From the third time the credentials are entered, the <code>Throttling</code> middleware will be in charge of managing the request.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724065942399/d7b5cd37-5f08-431c-ae28-c4f929fd3170.gif" alt class="image--center mx-auto" /></p>
<p>The role middleware is the one that manages the request when the credentials corresponding to the admin role are entered.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724065975029/a181499c-a197-4a7e-8c26-a35509ab916d.gif" alt class="image--center mx-auto" /></p>
<p>The most important thing about this pattern is not its concrete implementation but its ability to recognize the problem that this pattern can solve and when it can be applied. The specific implementation isn’t as important since that will vary depending on the programming language used.</p>
<p><a target="_blank" href="https://maxim-gorin.medium.com/stop-hardcoding-logic-use-the-chain-of-responsibility-instead-62146c9cf93a">https://maxim-gorin.medium.com/stop-hardcoding-logic-use-the-chain-of-responsibility-instead-62146c9cf93a</a></p>
<h2 id="heading-the-command-pattern">The Command Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724239078858/9914fc40-531e-4eaf-a6b3-77600324cce7.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Command</strong> is a behavioral design pattern that turns a request into a stand-alone object contains all information about the request. This transformation lets you pass requests as a method arguments, delay or queue a request's execution, and support undoable operations.</p>
</blockquote>
<h3 id="heading-problem-1">Problem</h3>
<p>Imagine you are working on a new text editor app. Your current task is to create a toolbar with a bunch of buttons for the editor's various operations. You create a very neat <code>Button</code> class that can be used for buttons on the toolbar, as well as for generic buttons in various dialogs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724239875208/34858867-e568-418a-b5ba-fdc8c9a504bb.png" alt class="image--center mx-auto" /></p>
<p>While all of these buttons look similar, they are all supposed to do different things. where would you put the code for the various click handlers of these buttons? The simplest solution is to create a ton of subclasses for each place where the button is used. These classes would contain the code that would have to be executed on a button click.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724240263789/16da2495-1dc7-4f53-883c-982f004750f7.png" alt class="image--center mx-auto" /></p>
<p>Before long, you realize that this approach is deeply flawed. First, you have an enormous number of subclasses, and that would be ok if you weren't risking breaking the code in these subclasses each time you modify the base <code>Button</code> class. Put simply, your GUI code has become awkwardly dependent on the volatile code of the business logic.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724240599818/3cbcec83-99a2-49c0-a260-d0797cd45e2a.png" alt class="image--center mx-auto" /></p>
<p>And here is the ugliest part. Some operations, such as copying/pasting text, would need to be invoked from multiple places. For example, a user could click a small "Copy" button on the toolbar, or copy something via the context menu, or just hit <code>Ctrl + C</code> on the keyboard.</p>
<p>Initially, when our app only had the toolbar, it was ok to play the implementation of various operations into the button subclasses. In other words, having the code for copying text inside the <code>CopyButton</code> subclass was fine. But then, when you implement context menus, shortcuts, and other stuff, you have to either duplicate the operation’s code in many classes or make menus dependent on buttons, which is an even worse option.</p>
<h3 id="heading-solution-1">Solution</h3>
<p>Good software design is often based on the <em>principle of separation of concerns</em>, which usually results in breaking an app into layers. The most common example: a layer for the graphical user interface and another layer for the business logic. The GUI layer is responsible for rendering a beautiful picture on the screen, capturing any inputs, and showing results of what the user and the app are doing, however, when it comes to doing something important, like calculating the trajectory of the moon or composing an annual report, the GUI layer delegates the work to the underlying layer of business logic.</p>
<p>In the code it might look like this: a GUI object calls a method of a business logic object, passing it some arguments. This process is usually described as one object sending another a request.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724472743196/8ceaba36-a0fe-4a3e-8d02-09e17d6fa96f.png" alt class="image--center mx-auto" /></p>
<p>The Command pattern suggests that GUI objects shouldn't send these requests directly. Instead, you should extract all of the request details, such as the request being called, the name of the method, and the list of arguments into a separate <em>command</em> class with a single method that triggers this request.</p>
<p>Command objects serve as links between various GUI and business logic objects. From now on, the GUI object doesn't need to know what business object will receive the request and how it will be processed. The GUI object just triggers the command, which handles all the details.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724471315109/43c22eba-a2a5-4050-92ea-9207a4ba357f.png" alt class="image--center mx-auto" /></p>
<p>The next step is to implement your commands using the same interface. Usually, it has just a single execution method that takes no parameters. This interface lets you use various commands with the same request sender, without coupling it to concrete classes of commands. As a bonus, now you can switch command objects linked to the sender, effectively changing the sender's behavior at runtime.</p>
<p>You might have noticed one missing piece of the puzzle, which is the request parameters. A GUI object might have supplied the business-layer object with some parameters. Since the command execution method doesn't have any parameters, how would we pass the request details to the receiver? It turns out the command should be either pre-configured with this data or capable of getting it on its own.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724473339619/744da1cc-8ce1-4b93-b72d-a5fde4fd5fde.png" alt class="image--center mx-auto" /></p>
<p>Let's get back to our text editor. After we apply the Command pattern, we no longer need all of those classes to implement various click behaviors. It's enough to put a single field into the base <code>Button</code> class that stores a reference to a command object and makes the button execute that command with a click.</p>
<p>You will implement a bunch of command classes for every possible operation and link them with particular buttons, depending on the button's intended behavior.</p>
<p>Other GUI elements, such as menus, shortcuts, or entire dialogs, can be implemented in the same way. They will be linked to a command that gets executed when a user interacts with the GUI elements. As you have probably guessed by now, the elements related to the same operations will be linked to the same commands, preventing any code duplication.</p>
<p>As a result, commands become a convenient middle layer that reduces the coupling between the GUI and business logic layers. And that is only a fraction of the benefits that the Command pattern can offer!</p>
<h3 id="heading-real-world-analogy">Real-World Analogy</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724475373893/d2be5b40-d7b9-4d84-91b8-9cf44bc6f240.png" alt class="image--center mx-auto" /></p>
<p>After a long walk through the city, you get to a nice restaurant and sit at the table by the window. A friendly waiter approaches you and quickly takes an order, writing it down on the piece of paper. The waiter goes to the kitchen and sticks the order on the wall. After a while, the order gets to the chef, who reads it and cooks the meal accordingly. The cook places the meal on the tray along with the order. The waiter discovers the tray, checks the order to make sure everything is as you want it, and brings everything to your table.</p>
<p>The order paper serves as a command. It remains in a queue until the chef is ready to serve it. The order contains all the relevant information required to cook the meal. It allows the chef to start cooking right away instead of running around clarifying the order details from you directly.</p>
<h3 id="heading-example">Example</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724499570063/cfb9776a-225c-441f-9e80-df53290083ea.webp" alt class="image--center mx-auto" /></p>
<p><strong>Implementation</strong></p>
<ul>
<li><p><strong>Define the Command Interface</strong>: Create an interface or abstract class that defines a method for executing a command. In our example, this is the <code>OrderCommand</code> interface with the <code>execute()</code> method.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> OrderCommand {
    <span class="hljs-built_in">void</span> execute();
  }
</code></pre>
</li>
<li><p><strong>Implement Concrete Commands</strong>: Create concrete classes that implement the command interface and perform specific actions. Examples include <code>OrderPizzaCommand</code>, <code>OrderBurgerCommand</code>, <code>CancelPizzaCommand</code>, and <code>CancelBurgerCommand</code>, each implementing the <code>execute()</code> method to perform the corresponding action on the <code>Chef</code> object.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">class</span> OrderPizzaCommand <span class="hljs-keyword">implements</span> OrderCommand {
    Chef _chef;

    OrderPizzaCommand(<span class="hljs-built_in">this</span>._chef);

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> execute() {
      _chef.preparePizza();
    }
  }

  <span class="hljs-keyword">class</span> CancelPizzaCommand <span class="hljs-keyword">implements</span> OrderCommand {
    Chef _chef;

    CancelPizzaCommand(<span class="hljs-built_in">this</span>._chef);

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> execute() {
      _chef.cancelPizza();
    }
  }

  <span class="hljs-keyword">class</span> OrderBurgerCommand <span class="hljs-keyword">implements</span> OrderCommand {
    Chef _chef;

    OrderBurgerCommand(<span class="hljs-built_in">this</span>._chef);

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> execute() {
      _chef.prepareBurger();
    }
  }

  <span class="hljs-keyword">class</span> CancelBurgerCommand <span class="hljs-keyword">implements</span> OrderCommand {
    Chef _chef;

    CancelBurgerCommand(<span class="hljs-built_in">this</span>._chef);

    <span class="hljs-meta">@override</span>
    <span class="hljs-built_in">void</span> execute() {
      _chef.cancelBurger();
    }
  }
</code></pre>
</li>
<li><p><strong>Create the Receiver Class</strong>: Define a class that performs the actual work. The <code>Chef</code> class includes methods for making and canceling pizza and burger orders.</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">class</span> Chef {
    <span class="hljs-built_in">void</span> preparePizza() {
      print(<span class="hljs-string">"Chef is preparing a pizza..."</span>);
    }

    <span class="hljs-built_in">void</span> cancelPizza() {
      print(<span class="hljs-string">"Chef is cancelling the pizza order."</span>);
    }

    <span class="hljs-built_in">void</span> prepareBurger() {
      print(<span class="hljs-string">"Chef is preparing a burger..."</span>);
    }

    <span class="hljs-built_in">void</span> cancelBurger() {
      print(<span class="hljs-string">"Chef is cancelling the burger order."</span>);
    }
  }
</code></pre>
</li>
<li><p><strong>Create the Invoker Class</strong>: Implement a class that stores and executes commands. The <code>Waiter</code> class holds a list of commands and provides methods to take orders (<code>takeOrder()</code>) and place orders (<code>placeOrders()</code>).</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">class</span> Waiter {
    List&lt;OrderCommand&gt; _orders = [];

    <span class="hljs-built_in">void</span> takeOrder(OrderCommand order) {
      _orders.add(order);
    }

    <span class="hljs-built_in">void</span> placeOrders() {
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> order <span class="hljs-keyword">in</span> _orders) {
        order.execute();
      }
      _orders.clear();
    }
  }
</code></pre>
</li>
</ul>
<p><strong>Usage</strong></p>
<ul>
<li><p><strong>Create the Chef</strong>: Instantiate the <code>Chef</code> class, which will perform the actual work of making and canceling orders.</p>
</li>
<li><p><strong>Create the Commands</strong>: Instantiate the concrete command classes, passing the <code>Chef</code> instance to their constructors.</p>
</li>
<li><p><code>OrderCommand orderPizza = OrderPizzaCommand(chef); OrderCommand orderBurger = OrderBurgerCommand(chef); OrderCommand cancelPizza = CancelPizzaCommand(chef); OrderCommand cancelBurger = CancelBurgerCommand(chef);</code></p>
</li>
<li><p><strong>Create the Waiter</strong>: Instantiate the <code>Waiter</code> class, which will act as the invoker of commands.</p>
</li>
<li><p><strong>Take and Place Orders</strong>: Use the <code>takeOrder()</code> method of the <code>Waiter</code> to queue commands and the <code>placeOrders()</code> method to execute them.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-built_in">void</span> main() {
  <span class="hljs-comment">// Create a Chef</span>
  Chef chef = Chef();

  <span class="hljs-comment">// Create commands</span>
  OrderCommand orderPizza = OrderPizzaCommand(chef);
  OrderCommand orderBurger = OrderBurgerCommand(chef);
  OrderCommand cancelPizza = CancelPizzaCommand(chef);
  OrderCommand cancelBurger = CancelBurgerCommand(chef);

  <span class="hljs-comment">// Create a Waiter</span>
  Waiter waiter = Waiter();

  <span class="hljs-comment">// Take orders</span>
  waiter.takeOrder(orderPizza);
  waiter.takeOrder(cancelBurger);
  waiter.takeOrder(orderBurger);
  waiter.takeOrder(cancelPizza);

  <span class="hljs-comment">// Place orders</span>
  waiter.placeOrders();
}
</code></pre>
<h2 id="heading-the-iterator-pattern">The Iterator Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724501030572/577c7054-c79a-47cb-bb70-70c8ab2f4b2f.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Iterator is a behavioral design pattern that lets you tranverse elements of a collection without exposing its underlying representation (list,stack,tree, etc.)</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/iterator">https://refactoring.guru/design-patterns/iterator</a></p>
</blockquote>
<h3 id="heading-problem-2">Problem</h3>
<p>Collections are one of the most used data types in programming. Nonetheless, a collection is just a container for a group of objects.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724582578988/a8f93d66-3b7c-45a2-a8cc-703b410baafa.png" alt class="image--center mx-auto" /></p>
<p>Most collections store their elements in simple lists. However, some of them are based on stacks, trees, graphs, and other complex data structures.</p>
<p>No matter how a collection is structured, it must provide some ways of accessing its elements so that other code can use these elements. This should be a way to go through each element of the collection without accessing the same elements over and over.</p>
<p>This may sound like an easy job if you have a collection based on a list. You just loop over all of the elements. But how do you sequentially traverse elements of a complex data structure, such as a tree? For example, one day you might be just fine with the depth-first traversal of a tree. Yet the next day you might require breadth-first traversal. And the next week, you might need something else, like random access to the tree elements.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724664517365/8d7f5e72-2ada-40f9-b536-2abb16845457.png" alt class="image--center mx-auto" /></p>
<p>Adding more and more traversal algorithms to the collection gradually blurs its primary responsibility, which is efficient data storage. Additionally, some algorithms might be tailored for a specific application, so including them in a generic collection class would be weird.</p>
<p>On the other hand, the client code that's supposed to work with various collections may not even care how they store their elements. However, since collections all provide different ways of accessing their elements, you have no option other than to couple your code to the specific collection classes.</p>
<h3 id="heading-solution-2">Solution</h3>
<p>The Iterator pattern's main idea is to extract a collection's traversal behavior into a separate object called an iterator.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724665927912/22d73308-8052-4f01-a9f5-05ce1433b542.png" alt class="image--center mx-auto" /></p>
<p>In addition to implementing the algorithm itself, an iterator object encapsulates all of the traversal details, such as the current position and how many elements are left till the end. Because of this, several iterators can go through the same collection at the same time, independently of each other.</p>
<p>Usually, iterators provide one primary method for fetching elements of the collection. The client can keep running this method until it doesn't return anything, which means that the iterator has traversed all of these elements.</p>
<p>All iterators must implement the same interface. This makes the client code compatible with any collection type or any traversal algorithm as long as there is a proper iterator. if you need a special way to traverse a collection, you just create a new iterator class, without having to change the collection or the client.</p>
<h3 id="heading-real-world-analogy-1">Real-World Analogy</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724667155159/34cfdfa0-7274-4d94-90c4-5cc5c696d4d7.png" alt class="image--center mx-auto" /></p>
<p>You plan to visit Rome for a few days and visit all of its main sights and attractions. But once there, you could waste a lot of time walking in circles, unable to find even the Colosseum.</p>
<p>On the other hand, we could buy a virtual guide app for your smartphone and use it for navigation. It's smart and inexpensive, and you could be staying at some interesting places for as long as you want.</p>
<p>A third alternative is that you could spend some of the trip's budget and hire a local guide who knows the city like the back of his hand. This guide would be able to tailor the tour to your liking, show you every attraction, and tell a lot of exciting stories. That will be even more fun, but, alas, more expensive, too.</p>
<p>All of these options - the random directions born in your head, the smartphone navigator, or the human guide - act as iterators over the vast collection of sights and attractions located in Rome.</p>
<h2 id="heading-the-mediator-pattern">The Mediator Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724671265242/c2261824-3cdd-4232-9be0-cb1e7f41d97b.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Mediator is a behavioral design pattern that lets you reduce chaotic dependencies between objects. The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/mediator">https://refactoring.guru/design-patterns/mediator</a></p>
</blockquote>
<h3 id="heading-problem-3">Problem</h3>
<p>Say you have a dialog for creating and editing customer profiles. It consists of various form controls such as text fields, checkboxes, buttons, etc.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724836157252/ec0a5460-623a-48ea-a730-69aa432ef4cb.png" alt class="image--center mx-auto" /></p>
<p>Some of the form elements may interact with others. For instance, selecting the "I have a dog" checkbox may reveal a hidden text field for entering the dog's name. Another example is the submit button which has to validate the values of all fields before saving the data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724836497610/97bcfae9-afc7-4763-8e35-049f7a90f47d.png" alt class="image--center mx-auto" /></p>
<p>By having this logic implemented directly inside the code of the form elements you make these element classes much harder to reuse in other forms of the app. For example, you won't be able to use that checkbox class inside another form, because it's coupled to the dog's text field. You can use either all the classes involved in rendering the profile form or none at all.</p>
<h3 id="heading-solution-3">Solution</h3>
<p>The Mediator pattern suggests that you should cease all direct communication between the components that you want to make independent of each other. Instead, these components must collaborate indirectly, by calling a special mediator object that redirect the calls to appropriate components. As a result, the components depend on only a single mediator class instead of being coupled to dozens of their colleagues.</p>
<p>In our example with the profile editing form, the dialog itself may act as the mediator. Most likely, the dialog class is already aware of its sub-elements, so you won't even need to introduce new dependencies into this class.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724837687354/5d653d5c-5d0b-43e1-bf2f-a4f5cf43cdb4.png" alt class="image--center mx-auto" /></p>
<p>The most significant change happens to the actual form elements. Let's consider the submit button. Previously, each time a user clicked on the button, it had to validate the values of all individual form elements. Now its single job is to notify the dialog about the click. Upon receiving this notification, the dialog itself performs the validations or passes the task to the individual elements. Thus, instead of being tied to a dozen form elements, the button is only dependent on the dialog class.</p>
<p>You can go further and make the dependency even looser by extracting the common interface for all types of dialogs. The interface would declare the notification method that all form elements can use to notify the dialog about events happening to those elements. Thus, our submit button should now be able to work with any dialog that implements that interface.</p>
<p>This way, the Mediator pattern lets you encapsulate a complex web of relations between various objects inside a single mediator object. the fewer dependencies a class has, the easier it becomes to modify, extend, or reuse that class.</p>
<h3 id="heading-real-world-analogy-2">Real-World Analogy</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724838820189/b391f110-6aa4-4184-8146-4a8865266642.png" alt class="image--center mx-auto" /></p>
<p>Pilots of aircraft that approach or depart the airport control area don't communicate directly with each other. Instead, they speak to an air traffic controller, who sits in a tall tower somewhere near the airstrips. Without the air traffic controller, pilots would need to be aware of every plan in the vicinity of the airport, discussing landing priorities with a committee of dozens of other pilots. That would probably skyrocket the airplane crash statistics.</p>
<p>The tower doesn't need to control the whole flight. It exists only to enforce constraints in the terminal area because the number of involved actors there might be overwhelming to a pilot.</p>
<h3 id="heading-when-to-use-it">When To Use It</h3>
<p>The <strong><em>Mediator</em></strong> is a good solution when we find ourselves with a system in which a set of objects communicate in a complex and direct way with each other, resulting in high coupling between them. Here are some common situations where using the <strong><em>Mediator</em></strong> pattern can be beneficial:</p>
<ol>
<li><p><strong>Complex communication between multiple objects</strong>: As we have said when we have several objects that need to communicate with each other in a complex and direct way, it can be difficult to understand and maintain. The <strong><em>Mediator</em></strong> pattern centralizes this complex communication into a single object, thus simplifying the communication flow and reducing coupling between objects.</p>
</li>
<li><p><strong>Reducing coupling</strong>: if you want to reduce coupling between the components of your system, the <strong><em>Mediator</em></strong> pattern can help. By centralizing communication between objects through a mediator, direct dependencies between objects are eliminated, making it easier to modify and maintain code.</p>
</li>
<li><p><strong>Facilitating component reusability</strong>: The <strong><em>Mediator</em></strong> pattern promotes the reusability of individual components by decoupling them from their interactions with other components. This allows objects to be more independent and therefore easier to reuse in different contexts or systems.</p>
</li>
</ol>
<p>In summary, the <strong><em>Mediator</em></strong> pattern is useful in situations where it is necessary to reduce coupling between objects, simplify communication between them, and facilitate the maintenance and evolution of code in complex systems.</p>
<p>Let's now move on to see the example of how to apply this system.</p>
<h3 id="heading-example-1">Example</h3>
<p>Let's take a look at the UML class diagram for this pattern to understand each of its elements:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724930786876/35523b09-96c1-4796-9f57-bc1aa47a4e9b.png" alt class="image--center mx-auto" /></p>
<p>The <strong><em>Mediator</em></strong> pattern typically includes the following main elements:</p>
<ul>
<li><p><strong>Mediator</strong>: Defines the interface for communication with <code>Colleague</code> objects.</p>
</li>
<li><p><strong>Concrete Mediator</strong>: Implements the <code>Mediator</code> interface and coordinate communication between <code>Colleague</code> objects.</p>
</li>
<li><p><strong>Colleague</strong>: Defines the interface for communication with other colleagues through the mediator.</p>
</li>
<li><p><strong>Concrete Colleague</strong>: Implements the Colleague interface and communicates its needs to the mediator, reacting to messages from the mediator.</p>
</li>
</ul>
<p>Let's start with the <code>Mediator</code> interface. This interface defines the contract that any mediator in the system must follow. In this case, it only has one method that we have called <code>notify</code> which receives the event sender (<code>sender</code>) and the event itself (<code>event</code>). This method is implemented by concrete mediators to handle communication between colleagues.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Colleague } <span class="hljs-keyword">from</span> <span class="hljs-string">"./colleague"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Mediator {
    notify(sender: Colleague, event: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">void</span>;
}
</code></pre>
<p>The next class is the concrete mediator. This class implements the <code>Mediator</code> interface. It has references to the colleagues with which it will interact. In this <code>notify</code> method, the mediator receives an event from a colleague and decides how to handle it based on the sender. In our case, the solution has been modeled using a switch control structure in which, depending on the colleague, we invoke a request handler. In this example, we only display messages on the screen to know that the notification has arrived correctly.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Colleague } <span class="hljs-keyword">from</span> <span class="hljs-string">"./colleague"</span>;
<span class="hljs-keyword">import</span> { Colleague1 } <span class="hljs-keyword">from</span> <span class="hljs-string">"./colleague1"</span>;
<span class="hljs-keyword">import</span> { Colleague2 } <span class="hljs-keyword">from</span> <span class="hljs-string">"./colleague2"</span>;
<span class="hljs-keyword">import</span> { Mediator } <span class="hljs-keyword">from</span> <span class="hljs-string">"./mediator"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ConcreteMediator <span class="hljs-keyword">implements</span> Mediator {
    <span class="hljs-keyword">private</span> colleague1: Colleague1;
    <span class="hljs-keyword">private</span> colleague2: Colleague2;


    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">colleague1: Colleague1, colleague2: Colleague2</span>) {
      <span class="hljs-built_in">this</span>.colleague1 = colleague1;
      <span class="hljs-built_in">this</span>.colleague2 = colleague2;
    }

    notify(sender: Colleague, event: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">void</span> {
        <span class="hljs-keyword">switch</span>(sender){
            <span class="hljs-keyword">case</span> <span class="hljs-built_in">this</span>.colleague1: <span class="hljs-built_in">this</span>.handleColleague1(event); <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> <span class="hljs-built_in">this</span>.colleague2: <span class="hljs-built_in">this</span>.handleColleague2(event); <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">default</span>: <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Unknown sender"</span>);
        }

    }
    <span class="hljs-keyword">private</span> handleColleague1(event){
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Event received by ConcreteMediator from Colleague1: "</span>, event);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"implements colleague1 logic"</span>);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"-----------------"</span>);
    }

    <span class="hljs-keyword">private</span> handleColleague2(event){
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Event received by ConcreteMediator from Colleague1: "</span>, event);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"implements colleague1 logic"</span>);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"-----------------"</span>);
    }
}
</code></pre>
<p>The next thing would be to define the colleague interface, which is the contract that all colleagues in the system must follow. In this case, they have 2 methods: <code>setMediator</code>, to set the mediator they belong to, and <code>action</code> , to perform an action that can generate an event.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Mediator } <span class="hljs-keyword">from</span> <span class="hljs-string">"./mediator"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Colleague {
    setMediator(mediator: Mediator): <span class="hljs-built_in">void</span>;
    action(): <span class="hljs-built_in">void</span>;
}
</code></pre>
<p>What remains to be seen of the <code>Mediator</code> pattern would be the colleagues who implement this interface. In this case, they receive the mediator dependency through the constructor, and it is stored in a private attribute of the mediator type. This reference is very useful for communicating with the mediator when an event occurs, this is done in the action method, where we can see how it is being modified and that an action has been performed that we want to be managed by the mediator through the notify method. This method is sent as a parameter to the class itself that sends the request and the message or parameter that we want to be managed from the mediator.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Colleague } <span class="hljs-keyword">from</span> <span class="hljs-string">"./colleague"</span>;
<span class="hljs-keyword">import</span> { Mediator } <span class="hljs-keyword">from</span> <span class="hljs-string">"./mediator"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Colleague1 <span class="hljs-keyword">implements</span> Colleague {
    <span class="hljs-keyword">private</span> mediator: Mediator;

    setMediator(mediator: Mediator): <span class="hljs-built_in">void</span> {
      <span class="hljs-built_in">this</span>.mediator = mediator;
    }

    action(): <span class="hljs-built_in">void</span> {
      <span class="hljs-built_in">this</span>.mediator.notify(<span class="hljs-built_in">this</span>, <span class="hljs-string">"Event from Colleague1"</span>);
    }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Colleague2 <span class="hljs-keyword">implements</span> Colleague {
    <span class="hljs-keyword">private</span> mediator: Mediator;

    setMediator(mediator: Mediator): <span class="hljs-built_in">void</span> {
      <span class="hljs-built_in">this</span>.mediator = mediator;
    }

    action(): <span class="hljs-built_in">void</span> {
      <span class="hljs-built_in">this</span>.mediator.notify(<span class="hljs-built_in">this</span>, <span class="hljs-string">"Event from Colleague2"</span>);
    }
}
</code></pre>
<p>At this point, we can think that the mediator could use another pattern to communicate with both colleagues and the mediator in a more reactive way, and this would be using the Observer pattern. We leave you with a task, once you have internalized the mediator pattern, how to apply the observer pattern together with it.</p>
<p>To conclude, we would have to see how this pattern is used in the client class.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Colleague1 } <span class="hljs-keyword">from</span> <span class="hljs-string">"./colleague1"</span>;
<span class="hljs-keyword">import</span> { Colleague2 } <span class="hljs-keyword">from</span> <span class="hljs-string">"./colleague2"</span>;
<span class="hljs-keyword">import</span> { ConcreteMediator } <span class="hljs-keyword">from</span> <span class="hljs-string">"./concrete-mediator"</span>;

<span class="hljs-keyword">const</span> colleague1 = <span class="hljs-keyword">new</span> Colleague1();
<span class="hljs-keyword">const</span> colleague2 = <span class="hljs-keyword">new</span> Colleague2();

<span class="hljs-keyword">const</span> mediator = <span class="hljs-keyword">new</span> ConcreteMediator(colleague1, colleague2);

colleague1.setMediator(mediator);
colleague2.setMediator(mediator);

colleague1.action();
colleague2.action();
</code></pre>
<p>In this class, the colleagues that interact with each other are instantiated. we relate the colleagues through the mediator, which is the one that will perform the mediation tasks between them.</p>
<p>On the other hand, we pass the mediator as a parameter to each colleague so that communication between the colleagues and the mediator can be achieved, that is, that the colleagues notify or warn that an event has occurred to the mediator.</p>
<p>Finally, each colleague will independently execute its action, which will be notified to the mediator and it will perform the different mediation tasks.</p>
<p>In this way we have decoupled the different colleagues from knowing each other, allowing new colleagues to be created without the need to know each other.</p>
<h2 id="heading-the-memento-pattern">The Memento Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725093871483/b8ec123e-34d0-41bd-b934-b0747814f398.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Memento</strong> is a behavioral design pattern that lets you save and restore the previous state of an object without revealing the details of its implementation.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/memento">https://refactoring.guru/design-patterns/memento</a></p>
</blockquote>
<h3 id="heading-problem-4">Problem</h3>
<p>Imagine you are creating a text editor app. In addition to simple text editing, your editor can format text, insert inline images, etc.</p>
<p>At some point, you decided to let users undo any operations carried out on the text. This feature has become so common over the years that nowadays people expect every app to have it. For the implementation, you chose to take a direct approach. Before performing any operation, the app records the state of all objects and saves them in some storage. Later, when a user decides to revert an action, the app fetches the latest snapshot from the history and uses it to restore the state of all objects.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725095378115/29c1d3c6-41ed-4ed3-977f-baa506cbd4f9.png" alt class="image--center mx-auto" /></p>
<p>Let's think about those state snapshots. How exactly would you produce one? You would probably need to go over all of the fields in an object and copy their values into storage. However, this would only work if the object had quite relaxed access restrictions to its contents. Unfortunately, most real objects won't let others peek inside them that easily, hiding all significant data in private fields.</p>
<p>Ignore that problem for now and let's assume that our objects behave like hippies: preferring open relations and keeping their state public. While this approach would solve the immediate problem and let you produce snapshots of an object's states at will, it still has some serious issues. In the future, you might decide to refactor some of the editor classes or add or remove some of the fields. Sounds easy, but this would also require changing the classes responsible for copying the state of the affected objects.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725097677148/84014284-5822-4eaa-a9a8-ea54fcac47e5.png" alt class="image--center mx-auto" /></p>
<p>But there is more. Let's consider the actual "snapshots" of the editor's state. What data does it contain? At a bare minimum, it must contain the actual text, cursor coordinates, current scroll, etc. To make a snapshot, you would need to collect these values and put them into some kind of container.</p>
<p>Most likely, you are going to store lots of these container objects inside some list that would represent the history. Therefore the container would probably end up being objects of one class. The class would have almost no methods, but lots of fields that mirror the editor's state. To allow other objects to write and read data to and from a snapshot, you would probably make its fields public. That would expose all the editor's states, private or not. Other classes would become dependent on every little change to the snapshot class, which would otherwise happen within private fields and methods without affecting outer classes.</p>
<p>It looks like we have reached a dead end: you either expose all internal details of classes, making them too fragile, or restrict access to their state, making it impossible to produce snapshots. Is there any other way to implement the "undo"?</p>
<h3 id="heading-solution-4">Solution</h3>
<p>All problems that we have just experienced are caused by broken encapsulation. Some objects try to do more than they are supposed to. To collect the data required to perform some action, they invade the private space of other objects instead of letting these objects perform the actual action.</p>
<p>The Memento pattern delegates the creation of state snapshots to the actual owner of that state, the originator object. Hence, instead of other objects trying to copy the editor's state from the outside, the editor class itself can make the snapshot since it has full access to its own state.</p>
<p>The pattern suggests storing the copy of the object's state in a special object called a <em>memento</em>. The contents of the memento aren't accessible to any other objects except the one that produced it. Other objects must communicate with mementos using a limited interface which may allow fetching the snapshot's metadata (creation time, the name of the performed operation, etc.) but not the original objects contained in the snapshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725102891043/9eaa5e12-34a8-4b85-b6ab-d09c2f38617e.png" alt class="image--center mx-auto" /></p>
<p>Such a restrictive policy lets you store mementos inside other objects, usually called <em>caretakers.</em> Since the caretakers work with the memento only via a limited interface, it's not able to tamper with the state stored inside the memento. At the same time, the originator has access to all fields inside the memento, allowing it to restore its previous at will.</p>
<p>In our text editor example, we can create a separate history class to act as the caretaker. A stack of mementos stored inside the caretaker will grow each time the editor is about to execute an operation. You could even render this stack within the app's UI, displaying the history of previously performed operations to a user.</p>
<p>When a user triggers the undo, the history grabs the most recent memento from the stack and passes it back to the editor, requesting a roll-back. Since the editor has full access to the memento, it changes its own state with the values taken from the memento.</p>
<h3 id="heading-example-2">Example</h3>
<p>Check out <a target="_blank" href="https://betterprogramming.pub/the-power-of-memento-design-pattern-in-javascript-309f8bb4d9f2">this article</a> to see how to implement the Memento pattern in Javascript.</p>
<p>\=&gt;&gt; There’s much to unpack here. See you in Part IV.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://betterprogramming.pub/understanding-the-chain-of-responsibility-design-pattern-2f44cdff61e5">https://betterprogramming.pub/understanding-the-chain-of-responsibility-design-pattern-2f44cdff61e5</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/command-design-pattern-explained-63d6df1b6ccb">https://levelup.gitconnected.com/command-design-pattern-explained-63d6df1b6ccb</a></p>
<p><a target="_blank" href="https://betterprogramming.pub/the-power-of-iterator-design-pattern-in-javascript-e8a9ec703fb5">https://betterprogramming.pub/the-power-of-iterator-design-pattern-in-javascript-e8a9ec703fb5</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/understanding-the-mediator-design-pattern-9dbfe19d6d71">https://levelup.gitconnected.com/understanding-the-mediator-design-pattern-9dbfe19d6d71</a></p>
<p><a target="_blank" href="https://blog.devgenius.io/implementing-undo-and-redo-functionality-with-the-memento-design-pattern-bca64a5281ea">https://blog.devgenius.io/implementing-undo-and-redo-functionality-with-the-memento-design-pattern-bca64a5281ea</a></p>
]]></content:encoded></item><item><title><![CDATA[Design Patterns Handbook - Part II]]></title><description><![CDATA[In our previous article, we explored five creational design patterns. Now, we'll delve into seven structural design patterns.
Let's get started!
Structural Design Patterns
Structural Design Patterns, as explained in “Design Patterns: Elements of Reus...]]></description><link>https://blog.tuanhadev.tech/design-patterns-handbook-part-ii</link><guid isPermaLink="true">https://blog.tuanhadev.tech/design-patterns-handbook-part-ii</guid><category><![CDATA[structural design pattern]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[design patterns]]></category><category><![CDATA[Object Relationship]]></category><category><![CDATA[Scalable web applications]]></category><category><![CDATA[code organization]]></category><category><![CDATA[code maintainability]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Fri, 09 Aug 2024 11:47:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/cNcX6PPjEm8/upload/e9d3ee7b05d2f583f9ddc881d2fc443e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In <a target="_blank" href="https://blog.tuanhadev.tech/design-patterns-handbook-part-i">our previous article</a>, we explored five creational design patterns. Now, we'll delve into seven structural design patterns.</p>
<p>Let's get started!</p>
<h1 id="heading-structural-design-patterns">Structural Design Patterns</h1>
<p>Structural Design Patterns, as explained in <a target="_blank" href="https://amzn.to/3Jr9a59">“Design Patterns: Elements of Reusable Object-Oriented Software” by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides</a>, focus on how objects and classes are composed to create flexible and robust software systems. These patterns highlight the relationships and interactions between different components, providing a framework for creating complex structures that are decoupled and maintainable.</p>
<p>There are seven widely recognized structural design patterns:</p>
<ul>
<li><p><strong>Adapter Pattern</strong></p>
</li>
<li><p><strong>Bridge Pattern</strong></p>
</li>
<li><p><strong>Composite Pattern</strong></p>
</li>
<li><p><strong>Decorator Pattern</strong></p>
</li>
<li><p><strong>Facade Pattern</strong></p>
</li>
<li><p><strong>Flyweight Pattern</strong></p>
</li>
<li><p><strong>Proxy Pattern</strong></p>
</li>
</ul>
<p>Next, we will examine each pattern in detail, including their use cases and code examples.</p>
<h2 id="heading-the-adapter-pattern">The Adapter Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720687087100/5252b672-a4e3-4299-8084-367e4283013a.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/adapter">https://refactoring.guru/design-patterns/adapter</a></p>
</blockquote>
<p>As shown above, the adapter simply converts an incompatible interface to a compatible form without changing the client and the customer.</p>
<p>The wheels on the car aren't fit to go on the train track. But that doesn't mean the car should be fitted with the train wheels. Instead, you can create a carrier that runs on the train wheels, and carry the car on the carrier to move it along the train track instead.</p>
<p>By doing so, your front-end and back-end aren't tied to each other. You are able to decouple the front-end components from your back-end API and treat them as independent entities as you are now using the adapter to pass data around your components.</p>
<p>Let's say we have this back-end API response:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720690869944/6bc5cb92-bfb1-4c58-bea6-06923c62d73b.webp" alt class="image--center mx-auto" /></p>
<p>and then we have this React component that accepts different props:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720690931617/5eb75c2b-9a78-4480-aacc-7a39cf475133.webp" alt class="image--center mx-auto" /></p>
<p>In this example, the Notification component accepts different prop names and also expects different values on <code>statusText</code>, and <code>typeText</code>.</p>
<p>\=&gt; To match or adapt the React component from the back-end API response, we create the adapter.</p>
<p>As I mentioned above, I got inspired by the builder design pattern, which is the result!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720691420933/534f693e-3253-4a96-8c83-c58a7dc767df.webp" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720691450008/b8eb615d-2ff0-437b-a6cf-836aff93441d.webp" alt class="image--center mx-auto" /></p>
<p>As you can see, we are now adapting the back-end API response to fit with the Notification component.</p>
<p>We have also added some extra logic mapping for FE purposes such as the <code>statusText</code> and <code>typeText</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720692171337/c3a42b1c-d3ba-4c07-81f6-4271ebac7115.webp" alt class="image--center mx-auto" /></p>
<p>And here's how we used it with <code>react-query</code> ! We’re using react-query’s select method to adapt from the raw data to what we need on this screen.</p>
<p>This isn't limited to <code>react-query</code> and can be applied to simple <code>fetch</code> API calls or whatever you are using to fetch data from the back-end.</p>
<p>It's a flexible and organized way to handle the mapping without too much distraction on your component level.</p>
<p>The Adapter design pattern has always been there. I'm pretty sure you have been using it on your projects, or work but just in a different implementation.</p>
<p>You might have implemented it with a so-called "mapper function" which is just a simple function instead of having a class.</p>
<p>This implementation is something I have created that was inspired by numerous things in works and persona projects.</p>
<p>The bottom line is, there are many implementations to achieve this. <strong>A design pattern gives you an idea of how to design to solve a recurring problem. It doesn't limit you on how you want to design the implementation.</strong></p>
<h2 id="heading-the-bridge-pattern">The Bridge Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720693166293/f4daac09-1a9e-426e-a8dd-fc57c94f6a3c.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Bridge is a structural design pattern that lets you split the large class or a set of closely related classes into two separate hierarchies - abstraction and implementation - which can be developed dependently of each other.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/bridge">https://refactoring.guru/design-patterns/bridge</a></p>
</blockquote>
<h3 id="heading-problem">Problem</h3>
<p>Say you have a geometric <code>Shape</code> class with a pair of subclasses: <code>Circle</code> and <code>Square</code>. You want to extend this class hierarchy to incorporate colors. So you plan to create <code>Red</code> and <code>Blue</code> shape subclasses. However, since you already have two subclasses, you need to create 4 class combinations such as <code>BlueCircle</code> and <code>RedSquare</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720954275185/7c5fabda-9fde-4c6c-a816-4e8f88c5ba0a.png" alt class="image--center mx-auto" /></p>
<p>Adding new shape types and colors to the hierarchy will grow it exponentially. For example, to add a triangle shape you would need to introduce 2 subclasses, one for each color. After that, adding a new color would require creating three subclasses, one for each shape type. The further we go, the worse it becomes.</p>
<h3 id="heading-solution">Solution</h3>
<p>This problem occurs because we are trying to extend the shape classes into two independent dimensions: by form and by color. That is a very common issue with class inheritance.</p>
<p>The Bridge attempts to solve this problem by switching inheritance to the object composition. What this means is that you extract one of the dimensions into a separate class hierarchy, so that the original classes will reference an object of the hierarchy, instead of having all of its state and behaviors within one class.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720955416418/13ebfff3-2199-484c-8974-32545b84dab0.png" alt class="image--center mx-auto" /></p>
<p>Following this approach, we can extract the color-related code into its own class with two subclasses: <code>Red</code> and <code>Blue</code>. The <code>Shape</code> class then gets a reference field pointing to one of the color objects. Now the shape can delegate any color-related work to the linked color object. The reference will act as a bridge between the <code>Shape</code> and <code>Color</code> classes. From now on, adding new colors won't require changing the shape hierarchy, and vice versa.</p>
<h3 id="heading-what-is-exactly-the-bridge-pattern">What is exactly the Bridge Pattern?</h3>
<p><strong>The Bridge</strong> is a software design pattern approach that creates a <code>bridge</code> between the two separate hierarchies and allows them to have multiple variations and evolve independently, increasing the system's flexibility.</p>
<p>In the big system, adding a new feature will make the number of class combinations grow exponentially, requiring more classes. Then, the bride can be a solution to deal with this problem by allowing classes to be divided into 2 hierarchies called <code>abstraction</code> and <code>implementation</code>:</p>
<ul>
<li><p><code>abstraction</code>: a high-level interface that references a <code>implementation</code> hierarchy.</p>
</li>
<li><p><code>implementation</code>: low-level implementation details.</p>
</li>
</ul>
<p>Now, the client can work with the abstraction without being tightly coupled to a specific implementation. This pattern favors object composition over class inheritance, following the principle "prefer composition over inheritance".</p>
<h3 id="heading-simple-typescript-example">Simple Typescript Example</h3>
<p>Let's say you have to build a design system that has many components and supports different themes. You are also expecting many changes in any theme details as well as component specifications. It's time to utilize the <strong>Bridge Pattern</strong>!</p>
<p>Here, the <code>Theme</code> interface serves as the implementation side of the Bridge Pattern. It declares the <code>provideColorSet()</code> method.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Implementation</span>
<span class="hljs-keyword">interface</span> Theme {
  provideColorSet(): <span class="hljs-built_in">void</span>
}

<span class="hljs-comment">// Concrete Implementation</span>
<span class="hljs-keyword">class</span> LightTheme <span class="hljs-keyword">implements</span> Theme {
  provideColorSet(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Provide color set using light colors...'</span>)
  }
}
<span class="hljs-keyword">class</span> DarkTheme <span class="hljs-keyword">implements</span> Theme {
  provideColorSet(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Provide color set using dark colors...'</span>)
  }
}
<span class="hljs-keyword">class</span> HighContrastTheme <span class="hljs-keyword">implements</span> Theme {
  provideColorSet(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Provide color set using high contrast colors...'</span>)
  }
}
</code></pre>
<p>The three different theme classes are concrete implementations of the Theme interface (<code>LightTheme</code>, <code>DarkTheme</code>, and <code>HighContrastTheme</code>). Each class implements the <code>provideColorSet()</code> method with specific logic for providing color sets.</p>
<p>The <code>Component</code> interface represents the <code>abstraction</code> side of the Bridge Pattern. It declares the <code>render()</code> method, which represents the high-level behavior that relies on the theme.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Abstraction</span>
<span class="hljs-keyword">interface</span> Component {
  render(): <span class="hljs-built_in">void</span>
}

<span class="hljs-comment">// Refined Abstraction</span>
<span class="hljs-keyword">class</span> Button <span class="hljs-keyword">implements</span> Component {
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> theme: Theme

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">theme: Theme</span>) {
    <span class="hljs-built_in">this</span>.theme = theme
  }

  render(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.theme.provideColorSet()
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Drawing a button.'</span>)
  }
}
<span class="hljs-keyword">class</span> Dialog <span class="hljs-keyword">implements</span> Component {
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> theme: Theme

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">theme: Theme</span>) {
    <span class="hljs-built_in">this</span>.theme = theme
  }

  render(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.theme.provideColorSet()
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Drawing a dialog.'</span>)
  }
}
<span class="hljs-keyword">class</span> Form <span class="hljs-keyword">implements</span> Component {
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> theme: Theme

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">theme: Theme</span>) {
    <span class="hljs-built_in">this</span>.theme = theme
  }

  render(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.theme.provideColorSet()
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Drawing a form.'</span>)
  }
}
</code></pre>
<p>The <code>Button</code>, <code>Dialog</code>, and <code>Form</code> classes are refined abstractions that implement the <code>Component</code> interface. Each refined abstraction depends on the <code>Theme</code> interface, which acts as a bridge to different concrete implementations of the theme. This separation allows for flexible composition and runtime selection of themes without modifying the components themselves.</p>
<p>On the client side, the instance of concrete implementations of <code>Theme</code>, and the instances of refined abstraction of <code>Component</code> is created. Then, the concrete theme implementation is passed as a parameter to the concrete refined abstraction.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Client Code</span>
<span class="hljs-keyword">const</span> lightTheme: Theme = <span class="hljs-keyword">new</span> LightTheme()
<span class="hljs-keyword">const</span> lightButton: Component = <span class="hljs-keyword">new</span> Button(lightTheme)

lightButton.render()
</code></pre>
<p>All combinations of any element and any theme are possible, still easy to manage complexity, and facilitate future modifications in the design system.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> darkTheme: Theme = <span class="hljs-keyword">new</span> DarkTheme()
<span class="hljs-keyword">const</span> darkDialog: Component = <span class="hljs-keyword">new</span> Dialog(darkTheme)

darkDialog.render()

<span class="hljs-keyword">const</span> highContrastTheme: Theme = <span class="hljs-keyword">new</span> HighContrastTheme()
<span class="hljs-keyword">const</span> highContrastForm: Component = <span class="hljs-keyword">new</span> Form(highContrastTheme)

highContrastForm.render()
</code></pre>
<h3 id="heading-use-it-or-avoid-it">Use it or Avoid it</h3>
<p><strong>When to use it</strong></p>
<p>This is especially useful if there are multiple variations and dimensions of change and you anticipate different variations or extensions in both the <code>abstraction</code> and <code>implementation</code> hierarchies.</p>
<p>if you want the flexibility to switch implementations at runtime, this pattern can be a good choice.</p>
<p><strong>When to avoid it</strong></p>
<p>if you have a straightforward scenario with only one <code>abstraction</code> and one corresponding <code>implementation</code>, introducing the Bridge pattern is unnecessary.</p>
<p>Also, if <code>abstraction</code> and <code>implementation</code> are tightly coupled so that they are unlikely to change independently, using this pattern might introduce unnecessary complexity with clear benefits.</p>
<p>In short, the Bridge pattern helps to manage complexity, improve flexibility, and decouple abstractions from their implementations.</p>
<h2 id="heading-the-composite-pattern">The Composite Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721037753250/1c13fcf0-686b-44f3-b315-e57721abd1e9.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Composite is a structural design pattern that lets you compose objects into tree structures and then work with these structures as if they were individual objects.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/composite">https://refactoring.guru/design-patterns/composite</a></p>
</blockquote>
<h3 id="heading-problem-1">Problem</h3>
<p>Using the Composite makes sense only when the core model of your app can be represented as a tree.</p>
<p>For example, imagine that you have two types of objects: <code>Products</code> and <code>Boxes</code>. A Box can contain multiple products as well as a number of small boxes. These little boxes can also hold some or even small boxes and so on.</p>
<p>Say you decide to create an ordering system that uses these classes. Orders could contain simple products without any wrapping, as well as boxes stuffed with products... and other boxes. How would you determine the total price of such an order?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721214174058/a9d25f1b-d8a6-469f-857e-b2bcef2b3ff8.png" alt class="image--center mx-auto" /></p>
<p>You could try the direct approach: unwrap all the boxes, go over all the products, and then calculate the total. That could be doable in the real world, but in the program, it's not as simple as running a loop. You have to know these classes <code>Products</code> and <code>Boxes</code> you are going through, the nesting level of the boxes and other nasty details beforehand. All of this makes the direct approach either too awkward or even impossible.</p>
<h3 id="heading-solution-1">Solution</h3>
<p>The Composite pattern suggests that you work with Products and Boxes through a common interface that declares the method for calculating the total prices.</p>
<p>How would this method work? For a product, it would simply return the product's price. For a box, it would go over each item the box contains, ask its price, and return the total for this box. If one of these items were a smaller box, that box would also start going over its contents, until the price of all inner components were calculated. A box could even add some extra cost to the final price, such as packaging cost.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721215206613/b2dee5a6-39e6-49a2-993a-4b5fed091641.png" alt class="image--center mx-auto" /></p>
<p>The greatest benefit of this approach is that you don't need to care about the concrete classes of objects that composite the tree. You don't need to know whether an object is a simple product or a sophisticated box. You can treat them all the same via the common interface. When you call a method, the objects themselves pass the request down the tree.</p>
<h3 id="heading-what-is-exactly-the-composite-pattern">What is exactly the Composite Pattern?</h3>
<p><strong>The Composite Pattern</strong> is a design pattern in object-oriented programming that allows you to treat individual objects and groups of objects uniformly. It lets you compose objects into tree structures to represent part-whole hierarchies.</p>
<p>The pattern consists of 2 main components: the <code>Component</code> and the <code>Composite</code>. The <code>Component</code> is the interface that defines the common operations that can be performed on both leaf and composite objects. The Composite is the class that implements the <code>Component</code> interface and contains other Composites and/or leaf objects.</p>
<p>The Composite Pattern is useful when you have a <em>hierarchy of objects</em> and you want to treat them all the same way, regardless of whether they are individual objects or collections of objects. For example, an employee hierarchy, deeply nested menu, or file system.</p>
<p>One of the key benefits of the Composite Pattern is that it allows you to add new objects to the hierarchy without changing the interface of existing objects. You can also define complex hierarchies that can be navigated using simple operations.</p>
<h3 id="heading-applying-composite-pattern-to-react">Applying Composite Pattern to React</h3>
<p>In React, we can use the Composite Pattern to create a hierarchy of components, where each component can be a leaf component or a composite component that can contain other components.</p>
<p>Let's say we want to create a menu component that can display nested items. Each item can either be a sub-menu or a leaf node with a label or a URL.</p>
<p>First, we will define our <code>MenuItem</code> interface:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> MenuItem {
  label: <span class="hljs-built_in">string</span>;
  url?: <span class="hljs-built_in">string</span>;
  subItems?: MenuItem[];
}
</code></pre>
<p>Each menu item has a label, and can optionally have a <code>url</code> and/or <code>subItems</code>. If subItems is defined, it should be an array of <code>MenuItem</code> representing the sub-menu.</p>
<p>Next, we will define our <code>Menu</code> component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> MenuProps {
  items: MenuItem[];
}

<span class="hljs-keyword">const</span> Menu: React.FC&lt;MenuProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ items }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    &lt;ul&gt;
      {items.map(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> (
        &lt;MenuItemComponent key={item.label} item={item} /&gt;
      ))}
    &lt;/ul&gt;
  );
};
</code></pre>
<p>The Menu component takes an array of <code>MenuItem</code> as its <code>items</code> prop. It maps over the <code>items</code> array and renders a <code>MenuItemComponent</code> for each item.</p>
<p>Now, we will define our <code>MenuItemComponent</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> MenuItemComponentProps {
  item: MenuItem;
}

<span class="hljs-keyword">const</span> MenuItemComponent: React.FC&lt;MenuItemComponentProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ item }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> hasSubItems = !!item.subItems;
  <span class="hljs-keyword">const</span> content = hasSubItems ? (
    &lt;Menu items={item.subItems} /&gt;
  ) : (
    &lt;a href={item.url}&gt;{item.label}&lt;/a&gt;
  );
  <span class="hljs-keyword">return</span> &lt;li&gt;{content}&lt;/li&gt;;
};
</code></pre>
<p>The <code>MenuItemComponent</code> takes a <code>MenuItem</code> as its <code>item</code> prop. If the item has sub-items, it renders another <code>Menu</code> component with the <code>subItems</code> array as its <code>items</code> prop. Otherwise, it renders an anchor tag with the <code>url</code> and <code>label</code> of the item.</p>
<p>With these components in place, we can create our menu hierarchy like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> menuItems: MenuItem[] = [
  {
    label: <span class="hljs-string">"Home"</span>,
    url: <span class="hljs-string">"/"</span>,
  },
  {
    label: <span class="hljs-string">"About"</span>,
    url: <span class="hljs-string">"/about"</span>,
  },
  {
    label: <span class="hljs-string">"Products"</span>,
    subItems: [
      {
        label: <span class="hljs-string">"Product 1"</span>,
        url: <span class="hljs-string">"/products/1"</span>,
      },
      {
        label: <span class="hljs-string">"Product 2"</span>,
        url: <span class="hljs-string">"/products/2"</span>,
      },
      {
        label: <span class="hljs-string">"Product 3"</span>,
        subItems: [
          {
            label: <span class="hljs-string">"Product 3.1"</span>,
            url: <span class="hljs-string">"/products/3/1"</span>,
          },
          {
            label: <span class="hljs-string">"Product 3.2"</span>,
            url: <span class="hljs-string">"/products/3/2"</span>,
          },
        ],
      },
    ],
  },
];

<span class="hljs-keyword">const</span> App: React.FC = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> &lt;Menu items={menuItems} /&gt;;
};
</code></pre>
<p>Here, we define an <code>menuItems</code> array with our menu hierarchy. We pass this array to the <code>Menu</code> component as its <code>items</code> prop. Finally, we render the <code>Menu</code> component inside our <code>App</code> component.</p>
<p>With this setup, our menu component will recursively render the nested menu hierarchy. if you want to add or remove menu items, we can simply modify the <code>menuItems</code> array. This is the power of the Composite Pattern - it allows us to treat nested collections of objects as if they were individual objects, making our code flexible and easier to reason about.</p>
<h2 id="heading-the-decorator-pattern">The Decorator Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721815435298/3b077965-297d-49c5-bc8f-07b6b3913837.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Decorator</strong> is a structural design pattern that lets you attachs new behaviours to objects by placing these objects inside special wrapper objects that contain the behaviours.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/decorator">https://refactoring.guru/design-patterns/decorator</a></p>
</blockquote>
<h3 id="heading-problem-2">Problem</h3>
<p>Imagine you are working on a notification library that lets other programs notify their users about important events.</p>
<p>The initial version of the library was based on <code>Notifier</code> class that had only a few fields, a constructor, and a single <code>send</code> method. The method could accept a message argument from a client and send a message to the list of emails that were passed to the Notifier via its constructor. A third-party app that acted as a client was supposed to create and configure the object once, and then use it each time something important happened.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721817783219/eb76e220-9305-4725-aa05-c95f0b099944.png" alt class="image--center mx-auto" /></p>
<p>At some points, you realize that users of the library expect more than just email notifications. Many of them would like to receive an SMS about critical issues. Others would like to be notified on Facebook, of course, the corporate users would love to get Slack notifications.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721818054218/3f6f6e72-f843-471f-a137-958a3e1ddca1.png" alt class="image--center mx-auto" /></p>
<p>How hard can that be? You extended a <code>Notifier</code> class and put the additional notification methods into new subclasses. Now the client was supposed to instantiate the desired notification class and use it for all further notifications.</p>
<p>But then someone reasonably asked you, "Why can't you use several notification types at once? if your house is on fire, you would probably want to be informed through every channel"</p>
<p>You tried to address that problem by creating special subclasses that combined several notification methods within one class. However, it quickly became apparent that this approach would bloat the code immensely, not only the library code but the client code as well.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721818746742/76860157-c2a9-48c4-8aa6-02c98175250a.png" alt class="image--center mx-auto" /></p>
<p>You have to find some other ways to structure notification classes so that their number won't accidentally break some Guinness record.</p>
<h3 id="heading-solution-2">Solution</h3>
<p>Extending a class is the first thing that comes to mind when you need to alter an object's behavior. However, inheritance has several serious caveats that you need to be aware of.</p>
<ul>
<li><p>Inheritance is static. You can't alter the behavior of an existing object at runtime. You can only replace the whole object with another one that is created from a different subclass.</p>
</li>
<li><p>Subclasses can have just one parent class. In most languages, inheritance doesn't let a class inherit behaviors of multiple classes at the same time.</p>
</li>
</ul>
<p>One of the ways to overcome these caveats is by using <em>Aggregation</em> and <em>Composition</em> instead of <em>Inheritance</em>. Both of the alternatives work almost the same way: one object has a reference to another and delegates it some work, whereas with inheritance, the object itself is able to do that work, inheriting the behaviors from its superclass.</p>
<p>With this new approach, you can easily substitute the linked "helper" object with another, changing the behaviors of the container at runtime. An object can use the behavior of various classes, having references to multiple objects and delegating them to all kinds of works. Aggregation/composition is the key principle behind many design patterns, including <em>Decorator.</em> On that note, let's return to the pattern discussion.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721985451761/2e4ebe2c-b37e-4f5e-9e90-b839178f029e.png" alt class="image--center mx-auto" /></p>
<p>"Wrapper" is the alternative nickname for the Decorator pattern that clearly expresses the main idea of the pattern. A wrapper is an object that can be linked with some target object. The wrapper contains the same set of methods as the target and delegates to it all requests it receives. However, the Wrapper may alter the result by doing something either before or after it passes the request to the target.</p>
<p>When does a simple wrapper become the real decorator? As I mentioned, the wrapper implements the same interface as the wrapped object. That's why from the client's perspective these objects are identical. Make the wrapper's reference field accept any object that follows that interface. This will let you cover an object in multiple wrappers, adding the combined behavior of all the wrappers to it.</p>
<p>In our notifications example, let's leave the simple email notification behavior inside the base <code>Notifier</code> class, but turn all other notification methods into decorators.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721989973852/c711c5b2-e8be-4680-84a2-833bcab5a56f.png" alt class="image--center mx-auto" /></p>
<p>The code would need to wrap a basic notifier object into a set of decorators that match the client's preferences. The resulting objects will be structured as a stack.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721990592035/525da55e-7067-4def-a2e8-14b6ba0b71a4.png" alt class="image--center mx-auto" /></p>
<p>The last decorator in the stack would be the object that the client actually works with. Since all decorators implement the same interface as the base notifier, the rest of the client code won't care whether it works with the "pure" notifier object or the decorated one.</p>
<p>We could apply the same approach to other behaviors such as formatting messages or composing the recipient list. The client can decorate the object with any custom decorator, as long as they follow the same interface with the others.</p>
<h3 id="heading-what-exactly-is-the-decorator-pattern">What exactly is the Decorator Pattern?</h3>
<p><strong>The Decorator Pattern</strong> is the design pattern that allows you to add functionality to an existing object without altering its structure. It's sometimes also called the <strong>Wrapper Pattern</strong> since it involves wrapping an object in another object to add behaviors. By wrapping an object in a decorator object, you can add new behavior to the object without modifying its original implementation. This allows you to create small, focused classes that do one thing well, and then combine them using decorators to create more complex behavior.</p>
<p>The <strong>Decorator Pattern</strong> is widely used in modern web development, particularly in front-end frameworks like <strong>React</strong> and <strong>Angular</strong>. In React, for example, components can be wrapped in higher-order components (HOCs) to add behavior to them.</p>
<p>HOCs - are essentially decorators that wrap a component and add behavior to it. For example, you could create an HOC that adds login functionality to a component, or one that adds authentication checks. HOCs are used extensively in React to create reusable code that can be applied to many different components.</p>
<h3 id="heading-example-of-decorator-design-pattern-in-typescript">Example of Decorator Design Pattern in Typescript</h3>
<p>Let's dive into how we can implement the Decorator Pattern in Typescript, using a coffee shop as our example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721994536650/a2c5c510-3b10-4951-b396-957435ae9927.webp" alt class="image--center mx-auto" /></p>
<p><strong>Step 1: Create the Component interface</strong></p>
<p>First, we define our "Component" interface, Coffee, which describes methods that will be implemented by both the base component and the decorators:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> Coffee {
  cost(): <span class="hljs-built_in">number</span>;
  description(): <span class="hljs-built_in">string</span>;
}
</code></pre>
<p><strong>Step 2: Implement the Component interface</strong></p>
<p>Next, we create the <code>SimpleCoffee</code> class that implements the <code>Coffee</code> interface. This is our base component when we start adding more behaviors.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> SimpleCoffee <span class="hljs-keyword">implements</span> Coffee {
  cost(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
  }

  description(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Simple coffee"</span>;
  }
}
</code></pre>
<p><strong>Step 3: Create the Base Decorator Class</strong></p>
<p>Then we define our <code>CoffeeDecorator</code> base class, which also implements the Coffee interface. The primary purpose of this class is to define the wrapping interface for all concrete decorators.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> CoffeeDecorator <span class="hljs-keyword">implements</span> Coffee {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">protected</span> coffee: Coffee</span>) {}

  <span class="hljs-keyword">abstract</span> cost(): <span class="hljs-built_in">number</span>;
  <span class="hljs-keyword">abstract</span> description(): <span class="hljs-built_in">string</span>;
}
</code></pre>
<p><strong>Step 4: Implement Concrete Decorators</strong></p>
<p>Next, we create concrete decorator classes <code>MilkDecorator</code>, <code>SugarDecorator</code>, <code>WhippedCreamDecorator</code> and <code>CaramelDecorator</code>, to extend the behavior of our <code>SimpleCoffee</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> MilkDecorator <span class="hljs-keyword">extends</span> CoffeeDecorator {
  cost(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.coffee.cost() + <span class="hljs-number">0.5</span>;
  }

  description(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.coffee.description() + <span class="hljs-string">", milk"</span>;
  }
}

<span class="hljs-keyword">class</span> SugarDecorator <span class="hljs-keyword">extends</span> CoffeeDecorator {
  cost(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.coffee.cost() + <span class="hljs-number">0.2</span>;
  }

  description(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.coffee.description() + <span class="hljs-string">", sugar"</span>;
  }
}

<span class="hljs-keyword">class</span> WhippedCreamDecorator <span class="hljs-keyword">extends</span> CoffeeDecorator {
  cost(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.coffee.cost() + <span class="hljs-number">0.7</span>;
  }

  description(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.coffee.description() + <span class="hljs-string">", whipped cream"</span>;
  }
}

<span class="hljs-keyword">class</span> CaramelDecorator <span class="hljs-keyword">extends</span> CoffeeDecorator {
  cost(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.coffee.cost() + <span class="hljs-number">0.6</span>;
  }

  description(): <span class="hljs-built_in">string</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.coffee.description() + <span class="hljs-string">", caramel"</span>;
  }
}
</code></pre>
<p><strong>Step 5: Use the Decorators</strong></p>
<p>Finally, we can use the decorators to add additional behavior to our <code>SimpleCoffee</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> coffee: Coffee = <span class="hljs-keyword">new</span> SimpleCoffee();
coffee = <span class="hljs-keyword">new</span> MilkDecorator(coffee);
coffee = <span class="hljs-keyword">new</span> SugarDecorator(coffee);
coffee = <span class="hljs-keyword">new</span> WhippedCreamDecorator(coffee);
coffee = <span class="hljs-keyword">new</span> CaramelDecorator(coffee);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Cost: $<span class="hljs-subst">${coffee.cost()}</span>`</span>); <span class="hljs-comment">// Outputs: Cost: $3.0</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Description: <span class="hljs-subst">${coffee.description()}</span>`</span>); <span class="hljs-comment">// Outputs: Description: Simple coffee, milk, sugar, whipped cream, caramel</span>
</code></pre>
<p>With these decorators, we have added milk, sugar, whipped cream, and caramel to our coffee dynamically, without modifying its underlying code. You can find the full code in this <a target="_blank" href="https://gist.github.com/myildizCH/98245467ca2d654613e1efb0efad72b2">gist.</a></p>
<p>\=&gt; The Decorator Pattern provides a powerful tool for dynamically extending the functionality of objects, keeping our code flexible, and manageable, and following the Open/Closed Principle. However, like all patterns, it’s not a silver bullet. Always consider if the added complexity is worthwhile for each specific use case. Happy decorating!</p>
<h2 id="heading-the-facade-pattern">The Facade Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722484211694/16da1294-b938-4628-854b-dd054eb9d8c5.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Facade</strong> is a structural design pattern that provides a simplified interface to the library, a framework, or any other complex set of classes.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/facade">https://refactoring.guru/design-patterns/facade</a></p>
</blockquote>
<h3 id="heading-problem-3">Problem</h3>
<p>Imagine you must make your code work with a broad set of objects that belong to a sophisticated library or framework. Ordinarily, you'd need to initialize all of those objects, keep track of dependencies, execute methods in the correct order, and so on.</p>
<p>As a result, the business logic of your classes would become tightly coupled with the implementation details of 3rd-party classes, making it hard to comprehend and maintain.</p>
<h3 id="heading-solution-3">Solution</h3>
<p>A facade is a class that provides a simple interface to a complex subsystem which contains lots of moving parts. A facade might provide limited functionality in comparison to working with the subsystem correctly. However, it includes only those features that clients really care about.</p>
<p>Having a facade is handy when you need to integrate your app with a sophisticated library that has dozens of features, but you just need a tiny bit of its functionality.</p>
<p>For instance, an app that uploads funny videos with cats to social media could potentially use a professional video conversion library. However, all that it really needs is a class with a single method <code>encode(filename, format)</code>. After creating such a class and connecting it with the video conversion library, you will have your first facade.</p>
<h3 id="heading-what-is-the-facade-design-pattern">What is the Facade Design Pattern?</h3>
<p>The Facade design pattern is a structural pattern that provides a simple interface to a complex system of structs, libraries, or subsystems. It's used to hide the system's complexity and provide an easy-to-use interface to the clients. <strong>The facade pattern is also known as a wrapper or an interface pattern</strong>. The Facade pattern also promotes loose coupling between the client code and the system, making it easier to modify the system without affecting the client code.</p>
<p><strong>The objectives of the Facade Pattern are the following:</strong></p>
<ul>
<li><p>Provide a simple interface to a complex subsystem.</p>
</li>
<li><p>Encapsulate the complexity of the subsystem.</p>
</li>
<li><p>Reduce coupling between the client and the subsystem.</p>
</li>
</ul>
<p><strong>The advantages of the Facade pattern are:</strong></p>
<ul>
<li><p>It simplifies the interface to the complex system, making it easier for clients to use.</p>
</li>
<li><p>It hides the system's complexity, making it easier to maintain and modify the system without affecting the client.</p>
</li>
<li><p>It decouples the client from the system, making it easier to maintain and modify the system without affecting the client.</p>
</li>
</ul>
<p><strong>The disadvantages of the Facade pattern are:</strong></p>
<ul>
<li><p>It can create an additional layer of abstraction, which can add complexity to the system.</p>
</li>
<li><p>It can make the system less flexible, as the Facade limits the client's access to the underlying system.</p>
</li>
</ul>
<h3 id="heading-example-of-the-facade-design-pattern-in-javascript">Example of the Facade Design Pattern in Javascript</h3>
<p>Let's pretend we are building a simple game and one of our first implementations of something will be a definition of a <code>Human</code> class. Other parts of our code will expect this human class to contain several body parts as properties: <code>Eye</code>, <code>Ear</code>, <code>Arm</code>, <code>Leg</code>, <code>Feet</code>, <code>Nose</code>, <code>Mouth</code>, <code>Neck</code>, and <code>Stomach</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Human {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">opts = {}</span>) {
    <span class="hljs-built_in">this</span>.leftEye = opts.leftEye
    <span class="hljs-built_in">this</span>.rightEye = opts.rightEye
    <span class="hljs-built_in">this</span>.leftArm = opts.leftArm
    <span class="hljs-built_in">this</span>.rightArm = opts.rightArm
    <span class="hljs-built_in">this</span>.leftFoot = opts.leftFoot
    <span class="hljs-built_in">this</span>.rightFoot = opts.rightFoot
    <span class="hljs-built_in">this</span>.leftEar = opts.leftEar
    <span class="hljs-built_in">this</span>.rightEar = opts.rightEar
    <span class="hljs-built_in">this</span>.nose = opts.nose
    <span class="hljs-built_in">this</span>.mouth = opts.mouth
    <span class="hljs-built_in">this</span>.neck = opts.neck
    <span class="hljs-built_in">this</span>.stomach = opts.stomach
  }
}

<span class="hljs-keyword">class</span> Eye {}
<span class="hljs-keyword">class</span> Ear {}
<span class="hljs-keyword">class</span> Arm {}
<span class="hljs-keyword">class</span> Leg {}
<span class="hljs-keyword">class</span> Feet {}
<span class="hljs-keyword">class</span> Nose {}
<span class="hljs-keyword">class</span> Mouth {}
<span class="hljs-keyword">class</span> Neck {}
<span class="hljs-keyword">class</span> Stomach {}
</code></pre>
<p>Let's now define a <code>Profile</code> class which has a method or setting of its profile character called <code>setCharacter</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Profile {
  setCharacter(character) {
    validateCharacter(character)
    <span class="hljs-built_in">this</span>.character = character
  }
}
</code></pre>
<p>In a real-world scenario, of course, it would be dozens of times longer than this so just keep in mind that we are focusing solely on the pattern and the problem it solves by presenting only the relative code.</p>
<p>We included an <code>validateCharacter</code> at the beginning of our <code>setCharacter</code> function because it's a necessary component of any software to validate constructed pieces to ensure that errors don't occur unknowingly. This also happens to be a great setup to demonstrate the usefulness of a <code>Facade</code>.</p>
<p>Here is the implementation:</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">validateCharacter</span>(<span class="hljs-params">character</span>) </span>{
  <span class="hljs-keyword">if</span> (!character.leftEye) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Missing left eye`</span>)
  <span class="hljs-keyword">if</span> (!character.rightEye) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Missing right eye`</span>)
  <span class="hljs-keyword">if</span> (!character.leftEar) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Missing left ear`</span>)
  <span class="hljs-keyword">if</span> (!character.rightEar) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Missing right ear`</span>)
  <span class="hljs-keyword">if</span> (!character.nose) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Missing nose`</span>)
  <span class="hljs-keyword">if</span> (!character.mouth) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Missing mouth`</span>)
  <span class="hljs-keyword">if</span> (!character.neck) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Missing neck`</span>)
  <span class="hljs-keyword">if</span> (!character.stomach) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Missing stomach`</span>)
}
</code></pre>
<p>So, inside our <code>validateCharacter</code> call it to proceed to check every part of the human body and throw an error if at least one body part is missing.</p>
<p>Let's try to use our code as if we were the client:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> bob = <span class="hljs-keyword">new</span> Human()
<span class="hljs-keyword">const</span> bobsProfile = <span class="hljs-keyword">new</span> Profile()
bobsProfile.setCharacter(bob)
</code></pre>
<p>Running the code will result in an error: <code>Error missing left eye</code></p>
<p>So, how does the client fix this? Easy! They just need to construct every single body part and be responsible for making them exist in the instance. Here is the code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> bobsLeftEye = <span class="hljs-keyword">new</span> Eye()
<span class="hljs-keyword">const</span> bobsRightEye = <span class="hljs-keyword">new</span> Eye()
<span class="hljs-keyword">const</span> bobsLeftEar = <span class="hljs-keyword">new</span> Ear()
<span class="hljs-keyword">const</span> bobsRightEar = <span class="hljs-keyword">new</span> Ear()
<span class="hljs-keyword">const</span> bobsNose = <span class="hljs-keyword">new</span> Nose()
<span class="hljs-keyword">const</span> bobsMouth = <span class="hljs-keyword">new</span> Mouth()
<span class="hljs-keyword">const</span> bobsNeck = <span class="hljs-keyword">new</span> Neck()
<span class="hljs-keyword">const</span> bobsStomach = <span class="hljs-keyword">new</span> Stomach()
<span class="hljs-keyword">const</span> bobsLeftArm = <span class="hljs-keyword">new</span> Arm()
<span class="hljs-keyword">const</span> bobsRightArm = <span class="hljs-keyword">new</span> Arm()
<span class="hljs-keyword">const</span> bobsLeftLeg = <span class="hljs-keyword">new</span> Leg()
<span class="hljs-keyword">const</span> bobsRightLeg = <span class="hljs-keyword">new</span> Leg()
<span class="hljs-keyword">const</span> bobsLeftFoot = <span class="hljs-keyword">new</span> Feet()
<span class="hljs-keyword">const</span> bobsRightFoot = <span class="hljs-keyword">new</span> Feet()

<span class="hljs-keyword">const</span> bob = <span class="hljs-keyword">new</span> Human()
bob.leftEye = bobsLeftEye
bob.rightEye = bobsRightEye
bob.leftEar = bobsLeftEar
bob.rightEar = bobsRightEar
bob.nose = bobsNose
bob.mouth = bobsMouth
bob.neck = bobsNeck
bob.stomach = bobsStomach
bob.leftArm = bobsLeftArm
bob.rightArm = bobsRightArm
bob.leftLeg = bobsLeftLeg
bob.rightLeg = bobsRightLeg
bob.leftFoot = bobsLeftFoot
bob.rightFoot = bobsRightFoot
</code></pre>
<p>Now our code runs without errors. However, if you went along hands-on you might have noticed that you only cared about creating a character and the profile, so we encountered a couple of unpleasant issues here:</p>
<ol>
<li><p>The code is longer</p>
</li>
<li><p>The code is more complex</p>
</li>
<li><p>The code is not very easy to use for the client (in comparison to the original three liner)</p>
</li>
<li><p>Redundancy - This is redundancy in multiple areas. one hard hit to the redundancy is the repetitive mentioning of <code>bob</code> throughout our code</p>
</li>
<li><p>We gave the ball to the client (in other words we forced users of our code to become responsible for constructing and passing in every single body). A lot of time this becomes a good thing - it's not uncommon that we want to give the client code the ability to call the shots. But this situation is much different. There is no point here in having them do the work if they choose to go straight to creating the profile and proceed solely with the profile's features.</p>
</li>
</ol>
<p>Now, let's make our <code>Facade</code> and define how it will solve our unpleasant issues for clients:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Profile {
  setCharacter(character) {
    <span class="hljs-keyword">if</span> (!character.leftEye) character.leftEye = <span class="hljs-keyword">new</span> Eye()
    <span class="hljs-keyword">if</span> (!character.rightEye) character.rightEyye = <span class="hljs-keyword">new</span> Eye()
    <span class="hljs-keyword">if</span> (!character.leftEar) character.leftEar = <span class="hljs-keyword">new</span> Ear()
    <span class="hljs-keyword">if</span> (!character.rightEar) character.rightEar = <span class="hljs-keyword">new</span> Ear()
    <span class="hljs-keyword">if</span> (!character.nose) character.nose = <span class="hljs-keyword">new</span> Nose()
    <span class="hljs-keyword">if</span> (!character.mouth) character.mouth = <span class="hljs-keyword">new</span> Mouth()
    <span class="hljs-keyword">if</span> (!character.neck) character.neck = <span class="hljs-keyword">new</span> Neck()
    <span class="hljs-keyword">if</span> (!character.stomach) character.stomach = <span class="hljs-keyword">new</span> Stomach()
    <span class="hljs-built_in">this</span>.character = character
  }
}

<span class="hljs-keyword">const</span> bob = <span class="hljs-keyword">new</span> Human()
<span class="hljs-keyword">const</span> bobsProfile = <span class="hljs-keyword">new</span> Profile()
bobsProfile.setCharacter(bob)
</code></pre>
<p>Our <code>Profile</code> becomes the <code>Facade</code> itself and effectively encapsulates every implementation of body parts as a fallback so that the client code only needs to focus on the interface provided by the <code>Profile</code>.</p>
<p>We not only give them the option to skip the unnecessary steps to construct and set each body part, but we also give them the option to be fully in control of that if they want to on their own.</p>
<p>Also, notice that the user of our code is tightly coupled to the interface that <code>Profile</code> exposes.</p>
<h3 id="heading-differences-between-the-adapter-and-flyweight-pattern"><strong>Differences Between the Adapter and Flyweight Pattern</strong></h3>
<p><strong>Facade vs Adapter</strong></p>
<p>Sometimes the facade design pattern can be mistaken for the <code>Adapter</code> design pattern. But the difference is that the <code>Facade</code> may expose an entirely new interface for the client to use whereas the <code>Adapter</code>’s intent is to be backward compatible with previous interfaces when seeking to extend with newer properties or behavior.</p>
<p><strong>Facade vs Flyweight</strong></p>
<p>In the facade, the client code is given an interface to work with that represents an entire system of objects (which can contain new copies of identical objects) while the client in the flyweight pattern is given an interface to produce objects that intend to be shared when identical which is an effective approach to preserve memory.</p>
<h2 id="heading-the-flyweight-pattern">The Flyweight pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722502843904/e57cec57-725d-4c54-b631-72b16e7ce22f.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Flyweight is a structural design pattern that lets you fit more objects into the available amount of RAM by sharing common parts of state between multiple objects instead of keeping all of the data in each object.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/flyweight">https://refactoring.guru/design-patterns/flyweight</a></p>
</blockquote>
<h3 id="heading-problem-4">Problem</h3>
<p>To have some fun after long working hours, you decided to create a simple game: players would be moving around the map and shooting each other. You choose to implement a realistic particle system and make it a distinctive feature of the game. Vast quantities of bullets and shrapnel from explosions should fly over the map and deliver a thrilling experience to the player.</p>
<p>Upon its completion, you pushed the last commit, built the game, and sent it to your friend for a test drive. Although the game was running flawlessly on your machine, your friend wasn't able to play for long. On his computer, the game kept crashing after a few minutes of gameplay. After spending several hours digging through debug logs, you discovered that the game crashed because insufficient amount of RAM. It turned out that your friend's rig was much less powerful than your computer, and that's why the problem emerged so quickly on his machine.</p>
<p>The actual problem was related to your particle system. Each particle, such as the bullet, a missable, or a piece of shrapnel was presented by a separate object containing plenty of data. At some point, when the carnage on a player's screen reaches its climax, the newly created particle no longer fits into the remaining RAM, so the program crashes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722872947846/4a3b0814-c9dd-4b3d-b073-e27050fa3ba6.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-solution-4">Solution</h3>
<p>On closer inspection of the <code>Particle</code> class, you may notice that the color and sprite fields consume a lot of memory than other fields. what's worse is that these two fields store almost identical data across all particles. For example, all bullets have the same color and sprite.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722936796629/54b5b850-b02e-4317-9f49-814cb8bd7396.png" alt class="image--center mx-auto" /></p>
<p>Other parts of a particle's state, such as coordinates, movement vector, and speed, are unique to each particle. After all, the values of these fields change over time. This data represents the always-changing context in which the particle exists, while the color and sprite remain constant for each particle.</p>
<p>The constant data of an object is usually called the <strong>intrinsic state</strong>. It lives within the object; other objects can only read it, not change it. The rest of the object's state, often altered "from the outside" by other objects, is called the <strong>extrinsic state</strong>.</p>
<p>The Flyweight pattern suggests that you stop storing the extrinsic state inside the object. Instead, you should pass this state on to specific methods that rely on it. Only the intrinsic state stays within the object, letting you it reuse in different contexts. As a result, you would need fewer of these objects since they only differ in the intrinsic state, which has much fewer variations in the extrinsic.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722938274222/29e1e155-c5f5-44a3-8630-9bcb16e275d4.png" alt class="image--center mx-auto" /></p>
<p>Let's return to our game. Assuming that we had extracted the extrinsic state from our particle class, only three different objects would suffice to represent all particles in the game: a bullet, a missile, and a piece of shrapnel. As you have probably guessed by now, an object that only stores the intrinsic is called a <strong>flyweight</strong>.</p>
<h3 id="heading-what-is-the-flyweight-design-pattern">What is the Flyweight Design Pattern?</h3>
<p>First, let's see the definition provided by the <a target="_blank" href="https://levelup.gitconnected.com/understanding-the-flyweight-design-pattern-f17346536e36#:~:text=provided%20by%20the-,Gang%20of%20Four%20book,-%3A">Gang of Four book</a>:</p>
<p><em>A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an independent object in each context: it's distinguishable from an instance of the object that is not shared.</em></p>
<p>On the other hand, flyweight objects can not make assumptions about the object in which they operate. The key concept here is the distinction between intrinsic and extrinsic states. The intrinsic state is stored in the flyweight; it consists of information that is independent of the flyweight's context, allowing it to be shared. The extrinsic state depends on the flyweight's context and varies with it, therefore, it can not be shared. Client objects are responsible for passing the extrinsic state to the flyweight when it is needed.</p>
<h3 id="heading-an-example-of-the-flyweight-design-pattern">An example of the Flyweight Design Pattern</h3>
<p>If you have used a Javascript library before, there is a good chance you have worked directly on some variation of a flyweight pattern given to you whether it was through a Javascript library, framework, or even the DOM.</p>
<p>Let's take a look at this array of objects that represents objects as DOM elements:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> elems = [
  {
    tagName: <span class="hljs-string">'div'</span>,
    style: { width: <span class="hljs-string">'28.5px'</span>, height: <span class="hljs-string">'20px'</span> },
    children: [
      { tagName: <span class="hljs-string">'input'</span>, style: { width: <span class="hljs-string">'28.5px'</span>, height: <span class="hljs-string">'20px'</span> } },
      { tagName: <span class="hljs-string">'input'</span>, style: { width: <span class="hljs-string">'28.5px'</span>, height: <span class="hljs-string">'20px'</span> } },
      { tagName: <span class="hljs-string">'select'</span>, style: { width: <span class="hljs-string">'28.5px'</span>, height: <span class="hljs-string">'20px'</span> } },
      { tagName: <span class="hljs-string">'input'</span>, style: { width: <span class="hljs-string">'28.5px'</span>, height: <span class="hljs-string">'20px'</span> } },
    ],
  },
]
</code></pre>
<p>If you look at the <code>children</code> array, notice three objects are structurally identical:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722944555461/867943d7-58b0-4b9f-a8b8-d4f95ae2d41a.webp" alt class="image--center mx-auto" /></p>
<p>This is already an issue because if we were to continue this practice and our objects grow larger our program would take a big hit to the performance because it will create three separate objects in memory although they are all structurally equivalent. Imagine if there were 1000?</p>
<p>When we go over real examples of the flyweight design pattern this is basically what the flyweight intends to do behind the scenes:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> inputElement = {
  tagName: <span class="hljs-string">'input'</span>,
  style: { width: <span class="hljs-string">'28.5px'</span>, height: <span class="hljs-string">'20px'</span> },
}

<span class="hljs-keyword">const</span> elems = [
  {
    tagName: <span class="hljs-string">'div'</span>,
    style: { width: <span class="hljs-string">'28.5px'</span>, height: <span class="hljs-string">'20px'</span> },
    children: [
      inputElement,
      inputElement,
      { tagName: <span class="hljs-string">'select'</span>, style: { width: <span class="hljs-string">'28.5px'</span>, height: <span class="hljs-string">'20px'</span> } },
      inputElement,
    ],
  },
]
</code></pre>
<p>Notice how <code>inputElement</code> is mentioned multiple times.</p>
<h2 id="heading-the-proxy-design-pattern">The Proxy Design Pattern</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722945798009/590cbdc4-6250-4101-aab1-80787ca39305.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Proxy</strong> is a structural design pattern that lets you provide a substitute or placeholder for another object. A proxy controls access to the original object, allowing you to perform something either before or after the request gets through to the original objects.</p>
<p><a target="_blank" href="https://refactoring.guru/design-patterns/proxy">https://refactoring.guru/design-patterns/proxy</a></p>
</blockquote>
<h3 id="heading-problem-5">Problem</h3>
<p>Why would you want to control access to an object? Here is an example: you have a massive object that consumes a vast amount of system resources. You need it from time to time, but not always.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723195624271/579ae9d0-0026-49d0-afb4-8658d8baad3b.png" alt class="image--center mx-auto" /></p>
<p>You could implement lazy initialization: create this object only when it's actually needed. All of the object's clients would need to execute some deferred initialization code. Unfortunately, this would probably cause a lot of code duplication.</p>
<p>In an ideal world, we would want to put this code directly into our object's class, but that isn't always possible. For instance, the class may be part of a closed 3rd-party library.</p>
<h3 id="heading-solution-5">Solution</h3>
<p>The Proxy pattern suggests that you create a new proxy class with the same interface as an original service object. Then you update your app so that it passes the proxy object to all of the original object's clients. Upon receiving the request from the client, the proxy creates a real service object and delegates all the work to it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723197810835/f6c1a8e6-e688-45bf-a478-11128ffda25c.png" alt class="image--center mx-auto" /></p>
<p>But what is the benefit? If you need to execute something either before or after the primary logic of the class, the proxy lets you do it without changing that class. Since the proxy implements the same interface as the original class, it can be passed to any client that expects a real service object.</p>
<h3 id="heading-real-world-analogy">Real-World Analogy</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723198697396/0f701e94-416d-4c84-9530-31d37d6b0f47.png" alt class="image--center mx-auto" /></p>
<p>A credit card is a proxy for a bank account, a proxy for a cash bundle. Both implement the same interface: they can be used to make a payment. A consumer feels great because there is no need to carry loads of cash around. A shop owner is also happy since the income from the transaction gets added electronically to the shop's bank account without the risk of losing a deposit or getting robbed on the way to the bank.</p>
<h3 id="heading-what-is-the-proxy-design-pattern">What is the Proxy Design Pattern?</h3>
<p>The first thing we will do, as with the other design patterns, is to look at the definition offered by the book "Design Patterns" by the Gang of Four:</p>
<p><strong><em>Provide a surrogate or placeholder for another object to control access to it.</em></strong></p>
<p>A proxy can perform additional operations (such as controlled access, lazy loading, etc) before accessing a real object. The most common uses of the proxy pattern according to its purpose are as follows:</p>
<ul>
<li><p><strong>Virtual Proxy</strong>: controls access to resources that are expensive to create, such as objects that require a lot of memory or processing time. It's used for lazy loading of an object.</p>
</li>
<li><p><strong>Protection Proxy:</strong> controls access to an object by providing different permissions to different users.</p>
</li>
<li><p><strong>Remote Proxy</strong>: allows access to an object that resides in a different space. For example, this proxy could handle all the necessary communication between the client and the server on different machines.</p>
</li>
</ul>
<p>Let's look at the UML class diagram to understand each of its elements of:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723202737569/13c89360-0c73-440e-a2bd-93a9e18239dc.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Subject</strong>: Defines a common interface for <code>RealSubject</code> and <code>Proxy</code> so that <code>Proxy</code> can be used in place of <code>RealSubject</code>.</p>
</li>
<li><p><strong>RealSubject</strong>: The real objects that the proxy represents.</p>
</li>
<li><p><strong>Proxy</strong>: Maintain a reference that allows the proxy to access the <code>RealSubject</code>. Provides an identical interface to that of <code>Subject</code> so it can substitute <code>RealSubject</code>. Controls access to <code>RealSubject</code> and can be responsible for its creation and deletion.</p>
</li>
</ol>
<h3 id="heading-an-example-of-a-proxy-design-pattern-in-react">An example of a Proxy Design Pattern in React</h3>
<p>Now, you should have a clear idea about the proxy design pattern. It's time to get your hands dirty and gain hands-on experience with React using Proxy.</p>
<p>React comes with its built-in features set to optimize the performance and overall responsiveness of the app. However, when combining the proxy design pattern with these features, you can further enhance the performance of the app with well-controlled object interactions and data access.</p>
<p><strong>Enhanced Security</strong></p>
<p>Proxy design patterns can be helpful in a React application to enhance security by providing layers of control over object interactions and access to sensitive data. Below, you can find a simple demonstration of this concept.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> fetchUserData = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-comment">// Place the network request here</span>
 <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Data fetching...'</span>);

 <span class="hljs-keyword">return</span> {
  username: <span class="hljs-string">'john_doe'</span>,
  password: <span class="hljs-string">'user_password'</span>,
 };
};

<span class="hljs-keyword">const</span> useSecureUserData = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-keyword">const</span> [userData, setUserData] = useState(<span class="hljs-literal">null</span>);

 <span class="hljs-keyword">const</span> isUserAdmin = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Implement your authorization logic here</span>
  <span class="hljs-comment">// For simplicity, assume logged user is admin</span>
  <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
 };

 useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> userProxy = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(fetchUserData(), {
   get(target, prop) {
    <span class="hljs-comment">// Check if the user is authorized to access the user password</span>
    <span class="hljs-keyword">if</span> (prop === <span class="hljs-string">'password'</span> &amp;&amp; !isUserAdmin()) {
     <span class="hljs-built_in">console</span>.warn(<span class="hljs-string">'Unauthorized access to password!'</span>);
     <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>; <span class="hljs-comment">// Return null or handle unauthorized access</span>
    }

    <span class="hljs-keyword">return</span> target[prop];
   },
  });

  setUserData(userProxy);
 }, []);

 <span class="hljs-keyword">return</span> userData;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> UserProfile = <span class="hljs-function">() =&gt;</span> {
 <span class="hljs-keyword">const</span> userData = useSecureUserData();

 <span class="hljs-keyword">if</span> (!userData) {
  <span class="hljs-keyword">return</span> &lt;div&gt;Loading...&lt;/div&gt;;
 }

 <span class="hljs-keyword">return</span> (
  &lt;div&gt;
   &lt;p&gt;Username: {userData.username}&lt;/p&gt;
   &lt;p&gt;Password: {userData.password}&lt;/p&gt;
  &lt;/div&gt;
 );
};
</code></pre>
<p>In this simple example, the <code>useSecureUserData</code> custom hook fetches the user data and creates a proxy object to validate user data before returning it. Here the <code>fetchUserData</code> returns the real object and <code>userProxy</code> is the Proxy object. Finally <code>UserProfile</code> component works as the client calling the proxy object.</p>
<p>While this example illustrates using a Proxy object for access management, it’s important to note that using Higher-Order Components (HOC), the Context API, or router guards are common and sometimes more conventional approaches in React. The choice depends on the specific requirements of your application and the desired level of access control.</p>
<h1 id="heading-roundup">Roundup</h1>
<p>I hope you found this to be valuable. Look out for Behavioral Patterns in the next article.</p>
<p>Happy Coding ❤️</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://refactoring.guru/">https://refactoring.guru/</a></p>
<p><a target="_blank" href="https://javascript.plainenglish.io/how-i-use-adapter-pattern-in-reactjs-cb331e9bef0c">https://javascript.plainenglish.io/how-i-use-adapter-pattern-in-reactjs-cb331e9bef0c</a></p>
<p><a target="_blank" href="https://365kim.medium.com/bridge-pattern-in-typescript-structural-design-pattern-2-65e519d3f578">https://365kim.medium.com/bridge-pattern-in-typescript-structural-design-pattern-2-65e519d3f578</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/best-practices-of-react-composite-pattern-for-hierarchical-components-b0e04d298cd7">https://levelup.gitconnected.com/best-practices-of-react-composite-pattern-for-hierarchical-components-b0e04d298cd7</a></p>
<p><a target="_blank" href="https://blog.bitsrc.io/decorator-design-pattern-in-typescript-701dfbf24420">https://blog.bitsrc.io/decorator-design-pattern-in-typescript-701dfbf24420</a></p>
<p><a target="_blank" href="https://medium.com/gitconnected/facade-design-pattern-in-golang-with-unit-tests-7089b558b94e">https://medium.com/gitconnected/facade-design-pattern-in-golang-with-unit-tests-7089b558b94e</a></p>
<p><a target="_blank" href="https://medium.com/better-programming/the-facade-design-pattern-in-javascript-d3843853b238">https://medium.com/better-programming/the-facade-design-pattern-in-javascript-d3843853b238</a></p>
<p><a target="_blank" href="https://betterprogramming.pub/the-power-of-flyweight-design-pattern-in-javascript-5593ae9fa858">https://betterprogramming.pub/the-power-of-flyweight-design-pattern-in-javascript-5593ae9fa858</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/understanding-the-proxy-design-pattern-4cdee9a43d25">https://levelup.gitconnected.com/understanding-the-proxy-design-pattern-4cdee9a43d25</a></p>
<p><a target="_blank" href="https://blog.bitsrc.io/proxy-design-pattern-with-react-c0b465980fbf">https://blog.bitsrc.io/proxy-design-pattern-with-react-c0b465980fbf</a></p>
]]></content:encoded></item><item><title><![CDATA[Design Patterns Handbook - Part I]]></title><description><![CDATA[Hi everyone! In this article, I will explain what design patterns are and why they are useful.
We will also go through some of the most popular design patterns out there and give examples for each of them. Let's go.
What are the Design Patterns?

Eac...]]></description><link>https://blog.tuanhadev.tech/design-patterns-handbook-part-i</link><guid isPermaLink="true">https://blog.tuanhadev.tech/design-patterns-handbook-part-i</guid><category><![CDATA[design patterns]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[creational patterns]]></category><category><![CDATA[Singleton Design Pattern]]></category><category><![CDATA[Factory Design Pattern]]></category><category><![CDATA[abstract factory]]></category><category><![CDATA[builder pattern]]></category><category><![CDATA[coding standards]]></category><dc:creator><![CDATA[Tuan Tran Van]]></dc:creator><pubDate>Thu, 04 Jul 2024 10:09:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/4P3clZbmRmA/upload/c62ecc1c82af6408800262128accf674.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi everyone! In this article, I will explain what design patterns are and why they are useful.</p>
<p>We will also go through some of the most popular design patterns out there and give examples for each of them. Let's go.</p>
<h1 id="heading-what-are-the-design-patterns">What are the Design Patterns?</h1>
<blockquote>
<p>Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in a way that you this solution a million times over, without ever doing this the same way twice.</p>
<p>--<strong><em>Christopher Alexander</em></strong></p>
</blockquote>
<p>Patterns provide a framework that can be applied to similar issues but may be solved in different ways, sometimes in the real world and other times in digital space.</p>
<p>Design patterns are reusable solutions to commonly occurring problems within a given context in software design. It's not a finished design that can be transformed directly into the app. Rather, It's a template to solve a recurring design problem in code.</p>
<p>Design Patterns are often confused with algorithms because both concepts describe typical solutions to some known problems. While an algorithm always defines a clear set of actions that can achieve some goal, a pattern is a more high-level description of a solution. The code of the same pattern applied to two different programs may be different.</p>
<p>Design Patterns are also often confused with Architecture Patterns. The architecture of an application refers to the larger structure of the application while a design pattern refers to a method of solving a specific type of problem, much more focused and lower level than the global structure of the system. <strong>Architecture</strong> focuses on the <strong>abstract view</strong> of the idea while <strong>design</strong> focuses on the <strong>implementation view</strong> of the idea.</p>
<p>The pattern is not a specific piece of code, but a concept for solving a particular problem.</p>
<h1 id="heading-importance-of-design-patterns">Importance of Design Patterns</h1>
<p>Design patterns play a pivotal role in software development, providing standardized solutions that enhance communications among developers and establish shared languages for discussing design principles. They act as a common vocabulary, facilitating seamless collaboration and enabling developers to effectively complex design ideas.</p>
<p>Design patterns offer several benefits for software development:</p>
<ul>
<li><p><strong>Reusability</strong>: Design patterns provide reusable solutions to common problems, reducing the need to reinvent the wheel and promoting code reuse.</p>
</li>
<li><p><strong>Flexibility</strong>: Design patterns are designed to be adaptable, allowing them to be tailored to specific requirements or contexts.</p>
</li>
<li><p><strong>Communication</strong>: Design patterns established a shared language among developers, improving communication and collaboration.</p>
</li>
<li><p><strong>Maintainability</strong>: Design patterns can lead to more maintainable code, making it easier to understand, modify, and extend over time.</p>
</li>
</ul>
<h1 id="heading-when-to-avoid-the-use-of-design-patterns">When to avoid the use of Design Patterns?</h1>
<p>There are situations where it's best to avoid or be cautious about the use of design patterns. Here are some cases when you have to avoid the use of design patterns:</p>
<ul>
<li><p><strong>Over-Engineering</strong>: Introducing design patterns in simple scenarios can lead to unnecessary complexity. It makes the code harder to understand and maintain, especially for new developers.</p>
</li>
<li><p><strong>Premature Optimization</strong>: Optimizing code prematurely by applying patterns that are meant to solve performance issues can be counterproductive. It's better to profile and understand the issues first before applying specific patterns to address them.</p>
</li>
<li><p><strong>Lack of understanding</strong>: Misapplying design patterns can introduce bugs and make the code harder to maintain. It's important to thoroughly understand the pattern and its consequences before integrating it into your codebase.</p>
</li>
<li><p><strong>Inappropriate context</strong>: Each design pattern is suited for specific types of problems. Using a pattern outside of its intended context can lead to awkward and inefficient solutions.</p>
</li>
<li><p><strong>Decreased Flexibility</strong>: Some patterns introduce structures that can be rigid and hard to change later. It's essential to balance the benefits of the pattern with the need for future flexibility.</p>
</li>
<li><p><strong>Readability and Maintainability Concerns</strong>: Design patterns can introduce additional layers of abstraction that might obscure the basic functionality of the code. This can make it harder for new developers to get up to speed and for existing developers to maintain the code.</p>
</li>
<li><p><strong>Performance Overheads</strong>: Some design patterns, like the Proxy or Observer patterns, can introduce additional layers of indirection or excessive event notifications, which might impact performance.</p>
</li>
</ul>
<h1 id="heading-type-of-design-patterns">Type of Design Patterns</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719047336748/6c7bf906-3f70-4442-bf18-d15b53f88a07.png" alt class="image--center mx-auto" /></p>
<p>There are about 23 patterns currently discovered(I hardly think that I will do them all...)</p>
<p>These 23 types can be classified into 3 types:</p>
<ul>
<li><p><strong>Creational</strong>: These patterns are designed for class instantiation. They can be either class-creation patterns or object-creational patterns.</p>
</li>
<li><p><strong>Structural</strong>: These patterns are designed with regard to a class's structure and composition. The main goal of most of these patterns is to increase the functionality of the classes involved, without changing much of its composition.</p>
</li>
<li><p><strong>Behavioral</strong>: These patterns are designed depending on how one class communicates with others.</p>
</li>
</ul>
<p><strong>Design Patterns Relationships:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719659407185/9450d844-30e3-4a0e-b42e-534df8c671e7.webp" alt class="image--center mx-auto" /></p>
<h2 id="heading-creational-design-patterns">Creational Design Patterns</h2>
<p>Creational design patterns abstract the instantiation process. They help make the system independent of how its objects are created, composed, and represented. A class creational pattern uses inheritance to vary the instantiated class, whereas an object creation pattern will delegate instantiation to another object.</p>
<p>Creational patterns give a lot of flexibility in what gets created, who creates it, how it gets created, and when.</p>
<p>These are two recurring themes in these patterns:</p>
<ul>
<li><p>They all encapsulate knowledge about what concrete class the systems use.</p>
</li>
<li><p>They hide how instances of these classes are created and put together.</p>
</li>
</ul>
<h3 id="heading-the-singleton-design-pattern">The Singleton Design Pattern</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719907471768/cc5db20c-6d4e-4ac1-bab4-559843c5e27f.png" alt class="image--center mx-auto" /></p>
<p>The singleton pattern only allows a class or object to have a single instance and it uses a global variable to store that instance. You can use lazy loading to make sure that there is only one instance of the class because it will only create the class when you need it.</p>
<p>That prevents multiple instances from being active at the same time which could cause weird bugs. Most of the time this gets implemented in the constructor. The goal of a singleton pattern is typically to regulate the global state of application.</p>
<p>An example of a singleton that you probably use all the time is your logger.</p>
<p>If you work with some of the front-end frameworks like React or Angular, you know all about how tricky it can be to handle logs coming from multiple components. This is a great example of singletons in action because you never want more than one instance of a logger object, especially if you are using some kind of error-tracking tool.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> FoodLogger {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-built_in">this</span>.foodLog = []
  }

  log(order) {
    <span class="hljs-built_in">this</span>.foodLog.push(order.foodItem)
    <span class="hljs-comment">// do fancy code to send this log somewhere</span>
  }
}

<span class="hljs-comment">// this is the singleton</span>
<span class="hljs-keyword">class</span> FoodLoggerSingleton {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-keyword">if</span> (!FoodLoggerSingleton.instance) {
      FoodLoggerSingleton.instance = <span class="hljs-keyword">new</span> FoodLogger()
    }
  }

  getFoodLoggerInstance() {
    <span class="hljs-keyword">return</span> FoodLoggerSingleton.instance
  }
}

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = FoodLoggerSingleton
</code></pre>
<p>Now you don't have to worry about losing logs from multiple instances because you only have one in your project. So when you want to log the food that has been ordered, you could use the same <code>FoodLogger</code> instance across multiple files or components.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// An example of a Customer class using the singleton</span>

<span class="hljs-keyword">const</span> FoodLogger = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./FoodLogger'</span>)

<span class="hljs-keyword">const</span> foodLogger = <span class="hljs-keyword">new</span> FoodLogger().getFoodLoggerInstance()

<span class="hljs-keyword">class</span> Customer {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">order</span>) {
    <span class="hljs-built_in">this</span>.price = order.price
    <span class="hljs-built_in">this</span>.food = order.foodItem
    foodLogger.log(order)
  }

  <span class="hljs-comment">// other cool stuff happening for the customer</span>
}

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = Customer
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">//An example of the Restaurant class using the same singleton as the Customer class</span>

<span class="hljs-keyword">const</span> FoodLogger = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./FoodLogger'</span>)

<span class="hljs-keyword">const</span> foodLogger = <span class="hljs-keyword">new</span> FoodLogger().getFoodLoggerInstance()

<span class="hljs-keyword">class</span> Restaurant {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">inventory</span>) {
    <span class="hljs-built_in">this</span>.quantity = inventory.count
    <span class="hljs-built_in">this</span>.food = inventory.foodItem
    foodLogger.log(inventory)
  }

  <span class="hljs-comment">// other cool stuff happening at the restaurant</span>
}

<span class="hljs-built_in">module</span>.<span class="hljs-built_in">exports</span> = Restaurant
</code></pre>
<p>With this singleton pattern in place, you don't have to worry about just getting logs from the main application file. You can get them anywhere in your code base and they will all go to the exact same instance of the logger, which means none of your logs should get lost due to new instances.</p>
<h3 id="heading-the-factory-design-pattern">The Factory Design Pattern</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719907542300/67846024-c549-4a24-95be-c84ea8ed79b9.png" alt class="image--center mx-auto" /></p>
<p>Factory pattern is one of the most common creation patterns. It loosely connects the application by hiding the implementation details from the client code using the interface. It leaves the creation of object instances to the factory implementation.</p>
<p>We will be using a typical example of a factory that creates different types of users: <code>Manager</code> and <code>Developer</code>, for the sake of simplicity. You can imagine there will be many more types in a real project.</p>
<p>Firstly, Let's define our <code>Manager</code> and <code>Developer</code> classes:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719221635302/0de51cf7-af4a-4e93-9535-9a52d90246a9.webp" alt class="image--center mx-auto" /></p>
<p>In the above code, we define an <code>IStaff</code> interface, so that both <code>Manager</code> and <code>Developer</code> classes implement it. It's essential for the Factory pattern to work, so the client doesn't need to know a particular class, only the interface.</p>
<p>Another notable thing is the use of <code>NullStaff</code> class(<a target="_blank" href="https://en.wikipedia.org/wiki/Null_object_pattern#:~:text=The%20advantage%20of%20this%20approach,perform%20some%20action%20on%20each.">Null Object Pattern</a>). It simplifies the client code and avoids run time bugs when an invalid user type is passed in.</p>
<p>Finally, we have the <code>UserFactory</code> implemented below and the <code>UserService</code> as a client that consumes the factory. The <code>UserService</code> doesn't know the <code>Manager</code> or <code>Developer</code> class. It just passes in a <code>userType</code> and gets a concrete instance of the user class back.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719929774780/01c501ec-eedd-4f38-a24c-b8ea524da693.webp" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://medium.com/@ignatovich.dm/factory-functions-in-react-creating-reusable-components-and-logic-4af026e434d8">https://medium.com/@ignatovich.dm/factory-functions-in-react-creating-reusable-components-and-logic-4af026e434d8</a></p>
<p><a target="_blank" href="https://codebyumar.medium.com/clean-code-with-the-factory-pattern-in-modern-js-31981a5c6242">https://codebyumar.medium.com/clean-code-with-the-factory-pattern-in-modern-js-31981a5c6242</a></p>
<h3 id="heading-the-abstract-factory-pattern">The Abstract Factory Pattern</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719907720516/5cd8c965-df99-44cb-8595-c633fddb6f52.png" alt class="image--center mx-auto" /></p>
<p>The abstract factory pattern is a creational pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.</p>
<p>This pattern comes under the Gang of Four (GoF) design patterns and is particularly useful when the system must be independent of how its objects are created, composed, and represented, and the system is configured with multiple families of objects.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Client Code</span>
<span class="hljs-keyword">const</span> payPalFactory = <span class="hljs-keyword">new</span> PayPalGatewayFactory();
<span class="hljs-keyword">const</span> payPalProcessor = payPalFactory.createPaymentProcessor();
<span class="hljs-keyword">const</span> payPalInvoiceGenerator = payPalFactory.createInvoiceGenerator();

payPalProcessor.processPayment();
payPalInvoiceGenerator.generateInvoice();

<span class="hljs-keyword">const</span> stripeFactory = <span class="hljs-keyword">new</span> StripeGatewayFactory();
<span class="hljs-keyword">const</span> stripeProcessor = stripeFactory.createPaymentProcessor();
<span class="hljs-keyword">const</span> stripeInvoiceGenerator = stripeFactory.createInvoiceGenerator();

stripeProcessor.processPayment();
stripeInvoiceGenerator.generateInvoice();
</code></pre>
<p>The Abstract Factory pattern involves defining interfaces for creating families of related or dependent objects, and concrete classes that implement these interfaces to create specific objects within those families.</p>
<p><strong>Keys Concept of the Abstract Factory Pattern</strong></p>
<ul>
<li><p><strong><em>Abstract Factory Interface:</em></strong> This is the core interface that declares the creation methods for various abstract products. It defines a set of methods, each responsible for creating a different product.</p>
<pre><code class="lang-typescript">  <span class="hljs-comment">// Abstract Factory Interface for Payment Gateways</span>
  <span class="hljs-keyword">class</span> PaymentGatewayFactory {
      createPaymentProcessor() {}
      createInvoiceGenerator() {}
  }
</code></pre>
</li>
<li><p><strong><em>Concrete Factories</em></strong>: These are the concrete implementations of the abstract factory interface. Each concrete is responsible for creating a family of products.</p>
<pre><code class="lang-typescript">  <span class="hljs-comment">// Concrete Factory for PayPal</span>
  <span class="hljs-keyword">class</span> PayPalGatewayFactory <span class="hljs-keyword">extends</span> PaymentGatewayFactory {
      createPaymentProcessor() {
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> PayPalPaymentProcessor();
      }

      createInvoiceGenerator() {
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> PayPalInvoiceGenerator();
      }
  }

  <span class="hljs-comment">// Concrete Factory for Stripe</span>
  <span class="hljs-keyword">class</span> StripeGatewayFactory <span class="hljs-keyword">extends</span> PaymentGatewayFactory {
      createPaymentProcessor() {
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> StripePaymentProcessor();
      }

      createInvoiceGenerator() {
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> StripeInvoiceGenerator();
      }
  }
</code></pre>
</li>
<li><p><strong><em>Abstract products:</em></strong> There are abstract product interfaces. They declare interfaces for a set of distinct but related products.</p>
<pre><code class="lang-typescript">  <span class="hljs-comment">// Abstract Product Interface for Payment Processor</span>
  <span class="hljs-keyword">class</span> PaymentProcessor {
      processPayment() {}
  }

  <span class="hljs-comment">// Abstract Product Interface for Invoice Generator</span>
  <span class="hljs-keyword">class</span> InvoiceGenerator {
      generateInvoice() {}
  }
</code></pre>
</li>
<li><p><strong><em>Concrete products:</em></strong> These are the concrete implementations of the abstract product interfaces.</p>
<pre><code class="lang-typescript">  <span class="hljs-comment">// Concrete Product for PayPal Payment Processor</span>
  <span class="hljs-keyword">class</span> PayPalPaymentProcessor <span class="hljs-keyword">extends</span> PaymentProcessor {
      processPayment() {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Processing payment with PayPal..."</span>);
      }
  }

  <span class="hljs-comment">// Concrete Product for PayPal Invoice Generator</span>
  <span class="hljs-keyword">class</span> PayPalInvoiceGenerator <span class="hljs-keyword">extends</span> InvoiceGenerator {
      generateInvoice() {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Generating invoice for PayPal..."</span>);
      }
  }

  <span class="hljs-comment">// Concrete Product for Stripe Payment Processor</span>
  <span class="hljs-keyword">class</span> StripePaymentProcessor <span class="hljs-keyword">extends</span> PaymentProcessor {
      processPayment() {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Processing payment with Stripe..."</span>);
      }
  }

  <span class="hljs-comment">// Concrete Product for Stripe Invoice Generator</span>
  <span class="hljs-keyword">class</span> StripeInvoiceGenerator <span class="hljs-keyword">extends</span> InvoiceGenerator {
      generateInvoice() {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Generating invoice for Stripe..."</span>);
      }
  }
</code></pre>
</li>
</ul>
<p><strong>Advantages of the Abstract Factory Pattern</strong></p>
<p>There are 3 main advantages of using this pattern:</p>
<ul>
<li><p>It <strong>ensures the creation of objects</strong> that are <strong>compatible</strong> and <strong>consistent</strong>. By using abstract factories, you guarantee that the created products are designed to be together, promoting system integrity and reducing the risk of competitive components.</p>
</li>
<li><p>It promotes <strong>flexibility</strong> and <strong>extensibility</strong> in a system. As requirements involve or new features need to be added, you can introduce new concrete factories that implement the abstract factory interface. This allows for the seamless addition of new families of related products without modifying existing client code.</p>
</li>
<li><p>it <strong>isolates the client code from the details of concrete classes</strong>. Clients interact with the abstract interfaces provided by the abstract factory, which shields them from the specifics of how the objects are created.</p>
</li>
</ul>
<p><strong>The difference between the Factory Pattern and the Abstract Factory Pattern</strong></p>
<p>The Factory Pattern and Abstract Factory Pattern are both creational design patterns used to encapsulate object creation. However, they differ in complexity and use cases.</p>
<ul>
<li><p><strong>Scope and Complexity</strong>:</p>
<ul>
<li><p><strong>Factory Pattern</strong>: Focuses on creating a single object. It’s simpler and used when the creation of an object involves some logic that’s better centralized.</p>
</li>
<li><p><strong>Abstract Factory Pattern</strong>: Focuses on creating families of related or dependent objects. It’s more complex and used when there are multiple types of objects to be created that are designed to work together.</p>
</li>
</ul>
</li>
<li><p><strong>Class Structure</strong>:</p>
<ul>
<li><p><strong>Factory Pattern</strong>: Typically involves one factory class with a method to create objects.</p>
</li>
<li><p><strong>Abstract Factory Pattern</strong>: Involves multiple factory classes (factories of factories), each responsible for creating different types of related objects.</p>
</li>
</ul>
</li>
<li><p><strong>Use Cases</strong>:</p>
<ul>
<li><p><strong>Factory Pattern</strong>: Useful when the exact type of the object to be created is not known until runtime, or when there is complex logic involved in object creation.</p>
</li>
<li><p><strong>Abstract Factory Pattern</strong>: Useful when a system needs to be independent of how its objects are created, composed, and represented, and when a family of related objects is designed to be used together.</p>
</li>
</ul>
</li>
</ul>
<p>In summary, the Factory Pattern is simpler. It focuses on the creation of single objects with some logic centralized in a factory method. In contrast, the Abstract Factory Pattern is more complex and is used to create families of related objects with multiple objects.</p>
<h3 id="heading-the-prototype-design-pattern">The Prototype Design Pattern</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719907751836/5bcc39d9-3362-4d57-8dd0-8684f5530163.png" alt class="image--center mx-auto" /></p>
<p>The prototype pattern is a creational design pattern that involves creating new objects by copying an existing object, known as the prototype. Instead of creating new instances through a constructor, objects are cloned from an existing object.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Prototype object</span>
<span class="hljs-keyword">const</span> carPrototype = {
  brand: <span class="hljs-string">'Generic'</span>,
  model: <span class="hljs-string">'Car'</span>,
  start: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Starting the <span class="hljs-subst">${<span class="hljs-built_in">this</span>.brand}</span> <span class="hljs-subst">${<span class="hljs-built_in">this</span>.model}</span>`</span>);
  }
};

<span class="hljs-comment">// Clone object</span>
<span class="hljs-keyword">const</span> myCar = <span class="hljs-built_in">Object</span>.create(carPrototype);
myCar.brand = <span class="hljs-string">'Toyota'</span>;
myCar.model = <span class="hljs-string">'Camry'</span>;

<span class="hljs-comment">// Customized object</span>
<span class="hljs-keyword">const</span> customCar = <span class="hljs-built_in">Object</span>.create(carPrototype);
customCar.brand = <span class="hljs-string">'Tesla'</span>;
customCar.model = <span class="hljs-string">'Model S'</span>;
customCar.autopilot = <span class="hljs-literal">true</span>;

<span class="hljs-comment">// Usage</span>
myCar.start(); <span class="hljs-comment">// Output: Starting the Toyota Camry</span>
customCar.start(); <span class="hljs-comment">// Output: Starting the Tesla Model S</span>
</code></pre>
<p>As we already know all <strong>child objects</strong> that are created from a <strong>Class</strong>, <strong>will inherit all the properties of the class</strong> that are under the object <strong>prototype.</strong> After inheriting, all the newly created objects will have all properties from the Class prototype to their <code>__proto __</code> property. See details <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">here</a>.</p>
<p>So the value of <code>__proto__</code> on any child objects of the Class (Constructor function), is a direct reference to the Class prototype. Whenever we try to access a property on an object that doesn't exist on an object directly, Javascript will go down to the prototype chain to see if the property is available within the prototype chain.</p>
<p><strong>Key Concepts</strong></p>
<p>There are 2 key components for the prototype pattern:</p>
<ul>
<li><p><strong>Prototype</strong>: This is the object that serves as the template for creating new objects. It's the object to be cloned.</p>
</li>
<li><p><strong>Clone</strong>: the new created by copying the prototype.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">// Prototype object</span>
<span class="hljs-keyword">const</span> carPrototype = {
  wheels: <span class="hljs-number">4</span>,
  start: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Engine started"</span>;
  },
  stop: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Engine stopped"</span>;
  },
};

<span class="hljs-comment">// Car constructor function</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Car</span>(<span class="hljs-params">make, model</span>) </span>{
  <span class="hljs-built_in">this</span>.make = make;
  <span class="hljs-built_in">this</span>.model = model;
}

<span class="hljs-comment">// Use Object.create to clone the prototype</span>
Car.prototype = <span class="hljs-built_in">Object</span>.create(carPrototype);

<span class="hljs-comment">// Create instances using the prototype</span>
<span class="hljs-keyword">const</span> car1 = <span class="hljs-keyword">new</span> Car(<span class="hljs-string">"Toyota"</span>, <span class="hljs-string">"Camry"</span>);
<span class="hljs-keyword">const</span> car2 = <span class="hljs-keyword">new</span> Car(<span class="hljs-string">"Honda"</span>, <span class="hljs-string">"Accord"</span>);

<span class="hljs-comment">// Test the instances</span>
<span class="hljs-built_in">console</span>.log(car1.wheels); <span class="hljs-comment">// Output: 4</span>
<span class="hljs-built_in">console</span>.log(car2.start()); <span class="hljs-comment">// Output: Engine started</span>

<span class="hljs-comment">// Modify a property for a specific instance</span>
car1.wheels = <span class="hljs-number">3</span>;
<span class="hljs-built_in">console</span>.log(car1.wheels); <span class="hljs-comment">// Output: 3</span>
<span class="hljs-built_in">console</span>.log(car2.wheels); <span class="hljs-comment">// Output: 4 (unchanged)</span>

<span class="hljs-comment">// Demonstrate encapsulation</span>
<span class="hljs-built_in">console</span>.log(car1.hasOwnProperty(<span class="hljs-string">"wheels"</span>)); <span class="hljs-comment">// Output: true</span>
<span class="hljs-built_in">console</span>.log(car1.hasOwnProperty(<span class="hljs-string">"start"</span>)); <span class="hljs-comment">// Output: false (inherited from prototype)</span>
</code></pre>
<p><strong>Advantages of the prototype pattern</strong></p>
<p>I think there are 3 advantages of using the prototype pattern:</p>
<ul>
<li><p><strong>Flexibility</strong>: It provides a flexible way to create new objects, allowing for dynamic changes during runtime.</p>
</li>
<li><p><strong>Performance</strong>: Object cloning can be more efficient than repeatedly invoking constructors, especially when dealing with complex object hierarchies.</p>
</li>
<li><p><strong>Encapsulation</strong>: It encapsulates the details of object creation within the prototype, reducing dependencies on concrete implementations.</p>
</li>
</ul>
<p>The biggest benefit of using this pattern in JavaScript is the <strong>performance</strong> boost gained compared to object-oriented classes. This means that when you define functions inside an object, they will be created by reference. In other words, all child objects will point to the same method instead of creating their own individual copies.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Warrior = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">name</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name
  <span class="hljs-built_in">this</span>.hp = <span class="hljs-number">100</span>
}

Warrior.prototype.bash = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">target</span>) </span>{
  target.hp -= <span class="hljs-number">15</span>
}

Warrior.prototype.omniSlash = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">target</span>) </span>{
  <span class="hljs-comment">// The target's hp may not be under 50 or this attack will fail on the opponent</span>
  <span class="hljs-keyword">if</span> (target.hp &lt; <span class="hljs-number">50</span>) {
    <span class="hljs-keyword">return</span>
  }
  target.hp -= <span class="hljs-number">50</span>
}

<span class="hljs-keyword">const</span> sam = <span class="hljs-keyword">new</span> Warrior(<span class="hljs-string">'Sam'</span>)
<span class="hljs-keyword">const</span> lenardo = <span class="hljs-keyword">new</span> Warrior(<span class="hljs-string">'Lenardo'</span>)

<span class="hljs-built_in">console</span>.log(sam.bash === lenardo.bash) <span class="hljs-comment">// true</span>
</code></pre>
<p>If we had instead defined them like this, then they are not the same. Essentially, Javascript has created another copy of (supposedly) the same method for each instance.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Warrior = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">name</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name
  <span class="hljs-built_in">this</span>.hp = <span class="hljs-number">100</span>

  <span class="hljs-built_in">this</span>.bash = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">target</span>) </span>{
    target.hp -= <span class="hljs-number">15</span>
  }

  <span class="hljs-built_in">this</span>.omniSlash = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">target</span>) </span>{
    <span class="hljs-comment">// The target's hp may not be under 50 or this attack will fail on the opponent</span>
    <span class="hljs-keyword">if</span> (target.hp &lt; <span class="hljs-number">50</span>) {
      <span class="hljs-keyword">return</span>
    }
    target.hp -= <span class="hljs-number">50</span>
  }
}

<span class="hljs-keyword">const</span> sam = <span class="hljs-keyword">new</span> Warrior(<span class="hljs-string">'Sam'</span>)
<span class="hljs-keyword">const</span> lenardo = <span class="hljs-keyword">new</span> Warrior(<span class="hljs-string">'Lenardo'</span>)

<span class="hljs-built_in">console</span>.log(sam.bash === lenardo.bash) <span class="hljs-comment">// false</span>
</code></pre>
<p>So if we don't use the prototype pattern as in the last example, how crazy would it be when we instantiate many instances? We would have cloned methods cluttering up memory that essentially do the same exact things, which don't even need to be copied unless they rely on state inside instances!</p>
<p><strong>Common Mistakes</strong></p>
<p>There are a few points that we need to pay attention to when working with prototype patterns.</p>
<p>Firstly, we need to understand the requirements and implications of <a target="_blank" href="https://levelup.gitconnected.com/understanding-shallow-and-deep-cloning-in-javascript-a-comprehensive-guide-a9e3b84590f2">shallow and deep cloning</a>, as the Prototype Pattern allows for both.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Prototype object</span>
<span class="hljs-keyword">const</span> carPrototype = {
  wheels: <span class="hljs-number">4</span>,
  start: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Engine started"</span>;
  },
  stop: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Engine stopped"</span>;
  },
};

<span class="hljs-comment">// Car constructor function</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Car</span>(<span class="hljs-params">make, model</span>) </span>{
  <span class="hljs-built_in">this</span>.make = make;
  <span class="hljs-built_in">this</span>.model = model;
}

<span class="hljs-comment">// Use Object.create to clone the prototype</span>
Car.prototype = <span class="hljs-built_in">Object</span>.create(carPrototype);

<span class="hljs-comment">// Create instances using the prototype</span>
<span class="hljs-keyword">const</span> car1 = <span class="hljs-keyword">new</span> Car(<span class="hljs-string">"Toyota"</span>, <span class="hljs-string">"Camry"</span>);
<span class="hljs-keyword">const</span> car2 = <span class="hljs-keyword">new</span> Car(<span class="hljs-string">"Honda"</span>, <span class="hljs-string">"Accord"</span>);

<span class="hljs-comment">// Test the instances</span>
<span class="hljs-built_in">console</span>.log(car1.wheels); <span class="hljs-comment">// Output: 4</span>
<span class="hljs-built_in">console</span>.log(car2.wheels); <span class="hljs-comment">// Output: 4 (both instances share the same prototype)</span>

<span class="hljs-comment">// Modify a property for one instance</span>
car1.wheels = <span class="hljs-number">3</span>;
<span class="hljs-built_in">console</span>.log(car1.wheels); <span class="hljs-comment">// Output: 3</span>
<span class="hljs-built_in">console</span>.log(car2.wheels); <span class="hljs-comment">// Output: 4 (unchanged for other instance)</span>

<span class="hljs-comment">// Demonstrate modifications affecting other instances</span>
carPrototype.wheels = <span class="hljs-number">6</span>; <span class="hljs-comment">// Modify the prototype</span>
<span class="hljs-built_in">console</span>.log(car1.wheels); <span class="hljs-comment">// Output: 3 (unchanged, as it has its own property now)</span>
<span class="hljs-built_in">console</span>.log(car2.wheels); <span class="hljs-comment">// Output: 6 (modified because it shares the prototype)</span>
</code></pre>
<p>Lastly, we must consider making prototype objects immutable to prevent unintentional changes during cloning.</p>
<h3 id="heading-the-builder-design-pattern">The Builder Design Pattern</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719907796260/175d7440-900b-4970-894d-97e5b527e114.png" alt class="image--center mx-auto" /></p>
<p>Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.</p>
<p><strong>Problem</strong></p>
<p>Imagine a complex object that requires laborious, step-by-step initialization of many fields and nested objects. Such initialization code is usually buried inside a monstrous constructor with lots of parameters. Or even worse, scattered all over the client code.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719912060787/6d30c0bd-c5b3-4913-b54a-d812191be2a8.png" alt class="image--center mx-auto" /></p>
<p>For example, let's think about how to create a <code>House</code> object. To build a simple house, you need to construct four walls and a floor, install a door, fit a pair of windows, and build a roof. But what if you want a bigger, brighter house, with a backyard and other goodies(like a heating system, plumbing, and electrical wiring)</p>
<p>The simplest solution is to extend the base <code>House</code> class and create a set of subclasses to cover all combinations of the parameters. But eventually, you will end up with a considerable number of classes. Any new parameter, such as a porch style, will require growing this hierarchy even more.</p>
<p>There is another approach that doesn't involve breeding subclasses. You can create a giant constructor right in the base <code>House</code> class with all possible parameters that control the <code>House</code> object. While this approach indeed eliminates the need for subclasses, it creates another problem.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719913454661/359d8dc9-2bf1-4767-b3a2-ce534df78af7.png" alt class="image--center mx-auto" /></p>
<p>In most cases, most of the parameters will be unused, making the <a target="_blank" href="https://refactoring.guru/smells/long-parameter-list">constructor calls pretty ugly</a>. For instance, only a fraction of houses will have swimming pools, so the parameters related to swimming pools will be useless nine times out of ten.</p>
<p><strong>Solution</strong></p>
<p>The Builder pattern suggests that you extract the object construction code out of its own class and move it to separate objects called Builders.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719913927167/2956f0a1-47f1-4a06-bc45-5905157a14b2.png" alt class="image--center mx-auto" /></p>
<p>This pattern organizes object construction into a set of steps (<code>buildWalls</code>, <code>buildDoor</code>, etc.).To create an object, you create a series of these steps on the builder object. The important part is that you don't need to call all of these steps. You can call only those steps that are necessary for producing a particular configuration of an object.</p>
<p>The factory pattern is also used to create objects, but it doesn't matter how they are created. The factory pattern is only concerned with the result of the creation, while the builder pattern not only gets the result but also participates in the specific process of creation, which is suitable for creating a complex compound object.</p>
<p><strong>The real-world example of the Builder Pattern in React</strong></p>
<p>One of the use cases for the Builder Pattern in React is creating immutable objects with many option parameters. This might sound a little complicated, but it just means you can use a User Buider to set various properties of a user object (name, email, password, role, etc.) and return a new user object with those properties. This makes it easier to create user objects with many different properties without writing tons of code.</p>
<p>Let me also explain how we can use the Builder pattern to simplify the creation of a User component with optional properties. Look at the example first:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">interface</span> UserProps {
  firstName?: <span class="hljs-built_in">string</span>;
  lastName?: <span class="hljs-built_in">string</span>;
  email?: <span class="hljs-built_in">string</span>;
  avatarUrl?: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">class</span> UserBuilder {
  <span class="hljs-keyword">private</span> props: UserProps;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-built_in">this</span>.props = {};
  }

  withFirstName(firstName: <span class="hljs-built_in">string</span>): UserBuilder {
    <span class="hljs-built_in">this</span>.props.firstName = firstName;
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }

  withLastName(lastName: <span class="hljs-built_in">string</span>): UserBuilder {
    <span class="hljs-built_in">this</span>.props.lastName = lastName;
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }

  withEmail(email: <span class="hljs-built_in">string</span>): UserBuilder {
    <span class="hljs-built_in">this</span>.props.email = email;
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }

  withAvatarUrl(avatarUrl: <span class="hljs-built_in">string</span>): UserBuilder {
    <span class="hljs-built_in">this</span>.props.avatarUrl = avatarUrl;
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }

  build(): JSX.Element {
    <span class="hljs-keyword">return</span> &lt;User {...this.props} /&gt;;
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">User</span>(<span class="hljs-params">props: UserProps</span>) </span>{
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {props.avatarUrl &amp;&amp; &lt;img src={props.avatarUrl} alt=<span class="hljs-string">"Avatar"</span> /&gt;}
      {props.firstName &amp;&amp; &lt;p&gt;{props.firstName}&lt;/p&gt;}
      {props.lastName &amp;&amp; &lt;p&gt;{props.lastName}&lt;/p&gt;}
      {props.email &amp;&amp; &lt;p&gt;{props.email}&lt;/p&gt;}
    &lt;/div&gt;
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> user1 = <span class="hljs-keyword">new</span> UserBuilder().withFirstName(<span class="hljs-string">"John"</span>).withEmail(<span class="hljs-string">"john@example.com"</span>).build();
  <span class="hljs-keyword">const</span> user2 = <span class="hljs-keyword">new</span> UserBuilder().withFirstName(<span class="hljs-string">"Jane"</span>).withLastName(<span class="hljs-string">"Doe"</span>).withAvatarUrl(<span class="hljs-string">"https://example.com/avatar.jpg"</span>).build();

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      {user1}
      {user2}
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Firstly, we define an <code>UserProps</code> interface that contains all the option properties. Then, we create an <code>User</code> class with these properties as its constructor parameters.</p>
<p>To create an <code>User</code> object with the <code>Builder</code> pattern, we define a <code>UserBuilder</code> class with methods for each optional property. These methods set the value of the corresponding property and return the <code>UserBuilder</code> instance itself to allow chaining. Finally, we define a build method that returns a new <code>User</code> object with the values set by the builder method.</p>
<p>Now, when we need to create a <code>User</code> component with certain properties, we can create a new instance of the <code>UserBuilder</code> class sets the desired properties using the builder method, and calls the build method to get a <code>User</code> object. We can pass this <code>User</code> object as a prop to the <code>User</code> component, which will render with the provided properties.</p>
<p>Using the <code>Builder</code> pattern allows us to create instances of the <code>User</code> component with only the desired properties, without having to pass all possible properties as separate props. This makes our code more concise and easier to maintain.</p>
<p><strong><em>You may ask why we even need to create a property chain if we can simply pass a parameter as a component attribute.</em></strong></p>
<p>Using Builder Pattern will give you some benefits when:</p>
<ul>
<li><p>There is some logic happening with the parameters and you want to abstract it.</p>
</li>
<li><p>We need to create some repetitive components and avoid boosting your JSX, you may wrap them into the Builder.</p>
</li>
</ul>
<h1 id="heading-roundup">Roundup</h1>
<p>We have explored all 5 design patterns of the Creational Patterns, including the Singleton Design Pattern, Factory Design Pattern, Abstract Factory Design Pattern, Prototype Design Pattern, and the Builder Design Pattern. I'm sure that you have already used these patterns even if you didn't realize it. :))</p>
<p>I hope you enjoyed this article and learned something new.</p>
<p>Cheers, and we'll see each other in Part II of the Design Pattern series.</p>
<h1 id="heading-references">References</h1>
<p><a target="_blank" href="https://refactoring.guru/">https://refactoring.guru/</a></p>
<p><a target="_blank" href="https://itnext.io/best-practices-of-react-builder-pattern-only-react-pro-know-25b4b93cd39c">https://itnext.io/best-practices-of-react-builder-pattern-only-react-pro-know-25b4b93cd39c</a></p>
<p><a target="_blank" href="https://betterprogramming.pub/the-prototype-pattern-in-javascript-bfe9ff433e6c">https://betterprogramming.pub/the-prototype-pattern-in-javascript-bfe9ff433e6c</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/exploring-prototype-pattern-in-javascript-c96820e246cf">https://levelup.gitconnected.com/exploring-prototype-pattern-in-javascript-c96820e246cf</a></p>
<p><a target="_blank" href="https://levelup.gitconnected.com/exploring-the-abstract-factory-pattern-efef088da96e">https://levelup.gitconnected.com/exploring-the-abstract-factory-pattern-efef088da96e</a></p>
<p><a target="_blank" href="https://medium.com/codex/factory-pattern-type-script-implementation-with-type-map-ea422f38862">https://medium.com/codex/factory-pattern-type-script-implementation-with-type-map-ea422f38862</a></p>
]]></content:encoded></item></channel></rss>