<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shubhra Pokhariya</title>
    <description>The latest articles on DEV Community by Shubhra Pokhariya (@shubhradev).</description>
    <link>https://dev.to/shubhradev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3462235%2Fa195c0cb-1004-4a1a-93f4-ecb8593c6884.jpg</url>
      <title>DEV Community: Shubhra Pokhariya</title>
      <link>https://dev.to/shubhradev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shubhradev"/>
    <language>en</language>
    <item>
      <title>Next.js 16 Broke My App in 4 Places and None of Them Threw an Error</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Wed, 27 May 2026 08:32:54 +0000</pubDate>
      <link>https://dev.to/shubhradev/nextjs-16-broke-my-app-in-4-places-and-none-of-them-threw-an-error-51mn</link>
      <guid>https://dev.to/shubhradev/nextjs-16-broke-my-app-in-4-places-and-none-of-them-threw-an-error-51mn</guid>
      <description>&lt;p&gt;The CI was green.&lt;/p&gt;

&lt;p&gt;Build passed. No TypeScript errors. No warnings. Everything looked clean. I clicked deploy and went to make tea.&lt;/p&gt;

&lt;p&gt;Came back, opened staging, and things were broken in ways that made no sense. A redirect wasn't working. Lint had silently disappeared from the build pipeline. One API route was throwing on the very first real request. And a revalidation call I'd written two weeks earlier was running but doing nothing.&lt;/p&gt;

&lt;p&gt;Not one of these showed up during the build. Everything looked completely fine until it wasn't.&lt;/p&gt;

&lt;p&gt;This is what actually happened during my Next.js 16 upgrade, and what to check before you ship yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;code&gt;middleware.ts&lt;/code&gt; stopped running and told me nothing
&lt;/h2&gt;

&lt;p&gt;My middleware file was fine. It compiled. The export was valid. TypeScript was happy.&lt;/p&gt;

&lt;p&gt;After upgrading to Next.js 16, it just stopped running on requests. No error. No deprecation warning. No sign of anything wrong in the terminal. The file was simply ignored.&lt;/p&gt;

&lt;p&gt;What happened: Next.js 16 replaced &lt;code&gt;middleware.ts&lt;/code&gt; with &lt;code&gt;proxy.ts&lt;/code&gt;. Same location in your project. Different filename. Different exported function name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before: middleware.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// After: proxy.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole change. File rename, function rename. But because the old file didn't throw anything, I assumed it was still running. I only caught it because a redirect I expected wasn't happening and I spent way too long looking at the wrong thing.&lt;/p&gt;

&lt;p&gt;One thing to know: if you need edge runtime behavior specifically, &lt;code&gt;middleware.ts&lt;/code&gt; still exists for that use case. In my case, the logic I had there stopped running after the upgrade. Renaming the file and export fixed it immediately. The codemod handles this automatically. But if you manually upgraded the package without running it, or if it missed a file, this one is completely invisible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before you ship:&lt;/strong&gt; rename the file, rename the export, test a route that depends on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;code&gt;revalidateTag('products')&lt;/code&gt; compiled, deployed, and silently did the wrong thing
&lt;/h2&gt;

&lt;p&gt;During the migration I wrote this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One argument. Totally normal in Next.js 15. I'd written it a couple of weeks earlier and hadn't thought about it since.&lt;/p&gt;

&lt;p&gt;In Next.js 16, the single-argument form is deprecated and produces a TypeScript error. But only if your &lt;code&gt;tsconfig&lt;/code&gt; is in strict mode. Mine wasn't. It had been set up on an older project years ago and never touched.&lt;/p&gt;

&lt;p&gt;So it compiled. It deployed. It ran. And it fell back to legacy invalidation behavior instead of the new SWR-based system. Pages weren't reflecting mutations. No error anywhere, just stale data that I attributed to other things for longer than I should have.&lt;/p&gt;

&lt;p&gt;The fix is just adding the second argument:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;// SWR, the recommended default&lt;/span&gt;
&lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;  &lt;span class="c1"&gt;// Immediate expiry, for webhooks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The codemod (&lt;code&gt;npx @next/codemod@canary upgrade latest&lt;/code&gt;) handles this. But if you wrote any revalidation calls after upgrading, or if the codemod missed a file, check manually.&lt;/p&gt;

&lt;p&gt;The real fix is turning on strict mode in your &lt;code&gt;tsconfig&lt;/code&gt;. That one change makes this a compile error instead of a silent runtime problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do it before anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;code&gt;next lint&lt;/code&gt; disappeared and my CI kept saying it passed
&lt;/h2&gt;

&lt;p&gt;This one sounds minor. It wasn't.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;next lint&lt;/code&gt; is completely removed in Next.js 16. Not deprecated. Not changed. Gone. The &lt;code&gt;eslint&lt;/code&gt; option in &lt;code&gt;next.config.ts&lt;/code&gt; is also gone. &lt;code&gt;next build&lt;/code&gt; no longer runs linting automatically.&lt;/p&gt;

&lt;p&gt;My CI was configured to run &lt;code&gt;next lint&lt;/code&gt; as a step. After the upgrade, that command no longer existed. Depending on how your CI handles missing commands, it might fail loudly or it might just succeed silently and move on. Mine moved on.&lt;/p&gt;

&lt;p&gt;So I was shipping code with no linting running, and the CI was reporting green. I only noticed when an obvious issue slipped through that I expected lint to catch.&lt;/p&gt;

&lt;p&gt;The migration is to run ESLint directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint ."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lint:fix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint . --fix"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The codemod creates &lt;code&gt;eslint.config.mjs&lt;/code&gt; and updates your package.json scripts. But your CI config is a separate file the codemod does not touch. Check both places.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. One component was still reading &lt;code&gt;params&lt;/code&gt; synchronously
&lt;/h2&gt;

&lt;p&gt;The codemod updated most of my pages correctly. But I had a layout file it missed. The component was accessing &lt;code&gt;params&lt;/code&gt; directly without awaiting it, which is fine in Next.js 15 but wrong in 16 where &lt;code&gt;params&lt;/code&gt; is now a Promise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before — Next.js 15&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// After — Next.js 16&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one did throw, but only on the first real request to that route in staging, not during the build. The build passed completely clean.&lt;/p&gt;

&lt;p&gt;If you have layouts, pages, or route handlers, search the whole codebase for direct &lt;code&gt;params.&lt;/code&gt; access and check that every one has been updated. Same goes for &lt;code&gt;searchParams&lt;/code&gt;, &lt;code&gt;cookies()&lt;/code&gt;, &lt;code&gt;headers()&lt;/code&gt;, and &lt;code&gt;draftMode()&lt;/code&gt;. All async now, all need awaiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern that connects all four
&lt;/h2&gt;

&lt;p&gt;None of these are caching bugs. They're upgrade bugs. The kind where the build passes, the code is technically valid, and the wrong behavior only shows up under a specific condition: a real redirect being triggered, a mutation needing to reflect, a lint issue reaching review, a specific route being hit.&lt;/p&gt;

&lt;p&gt;The codemod gets most of this. Run &lt;code&gt;npx @next/codemod@canary upgrade latest&lt;/code&gt; before you change anything else. Then check three things manually: grep for any &lt;code&gt;revalidateTag(&lt;/code&gt; with a single argument, check your CI config for &lt;code&gt;next lint&lt;/code&gt;, and turn on strict TypeScript. Those three cover most of what the codemod can miss.&lt;/p&gt;

&lt;p&gt;If you're already past the upgrade and dealing with caching behavior specifically, the previous posts in this series cover that. &lt;a href="https://dev.to/shubhradev/i-built-a-free-debugger-because-nextjs-16-use-cache-was-completely-invisible-during-development-4a8"&gt;The debugger I built to make cache behavior visible during development&lt;/a&gt; and &lt;a href="https://dev.to/shubhradev/7-nextjs-16-caching-bugs-that-compile-fine-and-break-silently-in-production-1cap"&gt;the seven bugs that compile clean and break silently in production&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also have a full step-by-step migration guide with before/after comparisons at &lt;a href="https://shubhra.dev/tutorials/nextjs-16-cache-components" rel="noopener noreferrer"&gt;shubhra.dev/tutorials/nextjs-16-cache-components&lt;/a&gt; if you want the complete reference.&lt;/p&gt;

&lt;p&gt;Which of these hit you? Or something I didn't mention here?&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>7 Next.js 16 Caching Bugs That Compile Fine and Break Silently in Production</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Thu, 21 May 2026 12:06:06 +0000</pubDate>
      <link>https://dev.to/shubhradev/7-nextjs-16-caching-bugs-that-compile-fine-and-break-silently-in-production-1cap</link>
      <guid>https://dev.to/shubhradev/7-nextjs-16-caching-bugs-that-compile-fine-and-break-silently-in-production-1cap</guid>
      <description>&lt;p&gt;I lost hours debugging a Next.js 16 caching issue that had no error, no warning, and only showed up in production.&lt;/p&gt;

&lt;p&gt;The Next.js 16 caching model is genuinely good. But it introduces a class of bugs that are harder to detect than anything in previous versions: bugs that look correct, compile without errors, deploy successfully, and then silently misbehave in production.&lt;/p&gt;

&lt;p&gt;These are the most common ones I've seen across real projects. Every one comes from real production incidents.&lt;/p&gt;

&lt;p&gt;(Assumes you have cacheComponents: true enabled in next.config.ts.)&lt;/p&gt;

&lt;p&gt;This is a follow-up to my &lt;a href="https://dev.to/shubhradev/i-built-a-free-debugger-because-nextjs-16-use-cache-was-completely-invisible-during-development-4a8"&gt;previous post&lt;/a&gt; where I built a dev-only debugger to surface these issues during development. That tool helps you detect them. This post breaks down the exact failure cases behind those warnings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 1: &lt;code&gt;'use cache'&lt;/code&gt; on the Wrapper Instead of Inside the Function
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This looks cached. It is not.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProducts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="nf"&gt;cacheLife&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hours&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;'use cache'&lt;/code&gt; directive tells the Next.js compiler to treat that function as a cache boundary. When you wrap it, the compiler sees the wrapper as the entry point. The inner function may be cached, but the wrapper becomes the execution boundary, so you still end up running it on every request.&lt;/p&gt;

&lt;p&gt;No error. No warning. Just a function running on every request when it should be cached.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_getProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="nf"&gt;cacheLife&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hours&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;cacheTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Wrapper receives the already-cached function&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProducts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;someWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_getProducts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule is simple: &lt;code&gt;'use cache'&lt;/code&gt; lives inside the data function, never on anything that wraps it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 2: Deprecated &lt;code&gt;revalidateTag&lt;/code&gt; That Compiles and Uses Legacy Behavior
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Next.js 15: correct&lt;/span&gt;
&lt;span class="c1"&gt;// Next.js 16: TypeScript error, silently uses legacy behavior in loose tsconfig&lt;/span&gt;
&lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Next.js 16, &lt;code&gt;revalidateTag&lt;/code&gt; without a second argument is deprecated and produces a TypeScript error. But if your &lt;code&gt;tsconfig&lt;/code&gt; is not in strict mode (common in older projects), it compiles cleanly and falls back to legacy invalidation behavior instead of the new SWR-based system.&lt;/p&gt;

&lt;p&gt;Pages stop reflecting mutations. No error anywhere.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="c1"&gt;// SWR, recommended for most content&lt;/span&gt;
&lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// Immediate expiry for webhooks/payments&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;npx @next/codemod@canary upgrade latest&lt;/code&gt; during your migration, it handles this automatically. But check your &lt;code&gt;tsconfig&lt;/code&gt; strictness regardless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 3: Tag String Mismatch Across Files
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/data.ts -- written by developer A&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="nf"&gt;cacheTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Tag is 'product-list'&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// app/actions/products.ts -- written by developer B&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProductData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO products ...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[...])&lt;/span&gt;
  &lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Different string, invalidates nothing&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two different strings. Zero errors. The product list never refreshes after a new product is created. Users see stale data until &lt;code&gt;cacheLife&lt;/code&gt; expires on its own.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/tags.ts -- one source of truth&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`product-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`user-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;

&lt;span class="c1"&gt;// Both files import from tags&lt;/span&gt;
&lt;span class="nf"&gt;cacheTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tag typos become TypeScript errors. The string mismatch bug becomes structurally impossible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 4: Server Action Mutation Where the Acting User Sees Stale Data
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateProductPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPDATE products SET price = $1 WHERE id = $2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`product-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;revalidateTag&lt;/code&gt; with any named profile uses stale-while-revalidate. It marks the cache as stale. The next request still gets the cached version while fresh data loads in the background.&lt;/p&gt;

&lt;p&gt;For the admin who just clicked save, that means they navigate to the product page and see the old price. Looks like the save failed. Causes confusion and duplicate mutations.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateTag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateProductPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPDATE products SET price = $1 WHERE id = $2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="nf"&gt;updateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`product-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c1"&gt;// Acting user sees change immediately&lt;/span&gt;
  &lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`product-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Everyone else gets SWR&lt;/span&gt;
  &lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;// Product list also refreshes&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;updateTag&lt;/code&gt; expires the cache entry immediately. The next request waits for fresh data. The admin sees their change. Everyone else gets the fast SWR treatment.&lt;/p&gt;

&lt;p&gt;Constraint: &lt;code&gt;updateTag&lt;/code&gt; only works inside Server Actions. In Route Handlers, use &lt;code&gt;revalidateTag(tag, { expire: 0 })&lt;/code&gt; instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 5: &lt;code&gt;updateTag&lt;/code&gt; in a Route Handler
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/webhooks/stripe/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;updateTag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;parseStripeWebhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;price.updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;updateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Throws at runtime&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This compiles. It deploys. On the first real webhook call from Stripe, it throws at runtime. &lt;code&gt;updateTag&lt;/code&gt; only works inside Server Actions. Calling it anywhere else throws.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;revalidateTag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;parseStripeWebhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;price.updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;  &lt;span class="c1"&gt;// Immediate expiry in Route Handlers&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bug 6: Short &lt;code&gt;cacheLife&lt;/code&gt; That Silently Affects PPR
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;LiveStockStatus&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="nf"&gt;cacheLife&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;seconds&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Seems right for live stock data&lt;/span&gt;
  &lt;span class="nf"&gt;cacheTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`stock-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetchStockLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cacheLife('seconds')&lt;/code&gt;, &lt;code&gt;revalidate: 0&lt;/code&gt;, and &lt;code&gt;expire&lt;/code&gt; under 5 minutes are automatically excluded from the PPR static shell. They become dynamic holes that run at request time.&lt;/p&gt;

&lt;p&gt;One component with &lt;code&gt;cacheLife('seconds')&lt;/code&gt; can push parts of the page out of the static shell and turn them into request-time work. No warning. The page still works. It just becomes fully dynamic without any obvious signal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix, if the data can tolerate a short delay:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;cacheLife&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;minutes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Now included in the static shell&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix, if it genuinely needs to be live:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Parent page&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StockSkeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LiveStockStatus&lt;/span&gt; &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Streams in after static shell */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second approach is the correct PPR pattern for truly dynamic data. The static shell renders instantly and the live data streams in after.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 7: Runtime API Inside a Cached Scope
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserHeader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cookieStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// Throws at build time&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookieStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cookies()&lt;/code&gt;, &lt;code&gt;headers()&lt;/code&gt;, and &lt;code&gt;draftMode()&lt;/code&gt; are runtime APIs. They read request-specific data. They cannot live inside a &lt;code&gt;'use cache'&lt;/code&gt; scope because cached output is stored and replayed across requests.&lt;/p&gt;

&lt;p&gt;This one at least throws at build time with "Uncached data was accessed outside of Suspense". But the error gives you no component name, no file path, and no useful stack trace. You get to play binary search across your codebase to find it.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Read runtime values OUTSIDE the cached scope&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserHeader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cookieStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cookieStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CachedUserProfile&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Pass the VALUE as a serializable prop to the cached component&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CachedUserProfile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="nf"&gt;cacheLife&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hours&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;cacheTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`user-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GuestGreeting&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;userId&lt;/code&gt; is a string so it becomes part of the cache key automatically. Different users produce different cache entries without any manual key construction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Common Thread
&lt;/h2&gt;

&lt;p&gt;None of these have good error messages. Five of the seven compile and deploy without complaint. The other two throw, but either without enough information to find the cause quickly or only after the first real production request.&lt;/p&gt;

&lt;p&gt;The pattern across all of them is the same: the new caching model requires explicit correctness. When you get something wrong, it does not always tell you.&lt;/p&gt;

&lt;p&gt;If you are in the middle of a Next.js 16 migration and want to catch these during development rather than in production, I ended up building a free dev-only debugger that logs cache misses, dynamic holes, missing tags, and deprecated invalidation calls directly in your terminal. Zero production cost, one &lt;code&gt;.tsx&lt;/code&gt; file: &lt;a href="https://shubhra.dev/snippets/nextjs-use-cache-debugger" rel="noopener noreferrer"&gt;Next.js cache debugger&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you want these patterns enforced at the type level so the wrong call is a compile error rather than a runtime surprise, the production enforcement layer is &lt;a href="https://shubhra.dev/snippets/nextjs-cache-pro" rel="noopener noreferrer"&gt;Cache Pro Kit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have you run into any of these? Or something even stranger? I'm curious what the distribution looks like across different kinds of projects.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>I built a free debugger because Next.js 16 'use cache' was completely invisible during development</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Tue, 19 May 2026 10:29:28 +0000</pubDate>
      <link>https://dev.to/shubhradev/i-built-a-free-debugger-because-nextjs-16-use-cache-was-completely-invisible-during-development-4a8</link>
      <guid>https://dev.to/shubhradev/i-built-a-free-debugger-because-nextjs-16-use-cache-was-completely-invisible-during-development-4a8</guid>
      <description>&lt;p&gt;I spent an afternoon debugging a component that kept re-fetching on every single request.&lt;/p&gt;

&lt;p&gt;It had &lt;code&gt;'use cache'&lt;/code&gt; right there in the code. I was confident it was working. It wasn't.&lt;/p&gt;

&lt;p&gt;The problem was placement. &lt;code&gt;'use cache'&lt;/code&gt; was on the wrapper function, not inside the actual data function. That one mistake makes Next.js ignore the directive entirely. No error, no warning, nothing in the terminal. Just a function running on every request when it should have been cached.&lt;/p&gt;

&lt;p&gt;Another time I wrote this in a Server Action during a Next.js 16 migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It compiled. It deployed. Pages stopped reflecting mutations. Calling &lt;code&gt;revalidateTag&lt;/code&gt; without a second argument is a TypeScript error in Next.js 16, but the runtime fell back to legacy behaviour silently. I only caught it when users started reporting stale data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next.js 16's new caching model is genuinely great. But during development it is a complete black box.&lt;/strong&gt; You add the directive, you assume it works, and you only find out otherwise when something breaks in production.&lt;/p&gt;

&lt;p&gt;So I built a small dev-only toolkit to make it visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it catches
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Silent cache misses&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a function runs more than once with identical arguments, you see this immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[cache-debug] ⚠  POSSIBLE CACHE MISS - RE-EXECUTION WITH SAME ARGS
  fn:   getProductById
  args: ["prod-123"]
  This function ran 2 times with identical args.
  If you expect caching: check 'use cache' is inside this function, not the wrapper.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That warning would have saved me that entire afternoon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Dynamic holes from short cacheLife&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cacheLife('seconds')&lt;/code&gt; silently excludes a component from the PPR static shell. It becomes fully dynamic. No warning anywhere, just a slower page that you cannot explain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[cache-debug] ⚡ DYNAMIC HOLE WARNING
  fn:       getLivePrice
  cacheLife 'seconds' is short-lived (&amp;lt; 5 minutes or revalidate: 0).
  Next.js 16 automatically EXCLUDES this from the PPR static shell.
  This function will run at request time, it is NOT prerendered.
  Fix: Use 'minutes' or longer if you want it in the static shell.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Missing cacheTag&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A cached function with no &lt;code&gt;cacheTag()&lt;/code&gt; can only expire by time. You cannot revalidate it on demand. Easy to miss when moving fast, painful to discover later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[cache-debug] 🏷  MISSING cacheTag WARNING
  fn:   getProductById
  No cacheTag() found. This function cannot be invalidated on demand.
  It will only expire when cacheLife runs out.
  Fix: Add cacheTag('your-tag') inside the function.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Deprecated revalidateTag&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Next.js 16, &lt;code&gt;revalidateTag('tag')&lt;/code&gt; without a second argument is a TypeScript error. The &lt;code&gt;logInvalidation&lt;/code&gt; helper catches it before your CI does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[cache-debug] ✗  DEPRECATED revalidateTag - MISSING SECOND ARG
  tag:     products
  revalidateTag('products') without a profile is deprecated in Next.js 16.
  Fix: revalidateTag('products', 'max')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. updateTag outside a Server Action&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Calling &lt;code&gt;updateTag&lt;/code&gt; outside a Server Action throws at runtime. The toolkit catches it at dev time before it reaches production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Repeated fetches&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;detectRepeatedFetch&lt;/code&gt; surfaces the same URL being hit multiple times in one render. Usually means a cache layer is missing entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Enable in &lt;code&gt;.env.local&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CACHE_DEBUG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not add this to &lt;code&gt;.env.production&lt;/code&gt;. The &lt;code&gt;NODE_ENV&lt;/code&gt; guard already ensures it is off in production, but keeping env files clean is good practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Wrap your cached functions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;'use cache'&lt;/code&gt; directive must stay inside the original function. &lt;code&gt;withCacheDebug&lt;/code&gt; is a regular wrapper and cannot be a cache boundary. If you put &lt;code&gt;'use cache'&lt;/code&gt; on the wrapper, the instrumentation gets cached instead of the data function, which is exactly the mistake the POSSIBLE CACHE MISS warning is designed to catch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cacheLife&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cacheTag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/cache&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withCacheDebug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/cache-debug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_getProductById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use cache&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;cacheLife&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hours&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;cacheTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`product-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM products WHERE id = $1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withCacheDebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_getProductById&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getProductById&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cacheLife&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hours&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product-{id}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getProductById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prod-123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero API change. The exported function works exactly the same everywhere you already call it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Log invalidation calls in Server Actions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateTag&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/cache&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;logInvalidation&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/cache-debug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateProductPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UPDATE products SET price = $1 WHERE id = $2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nf"&gt;logInvalidation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;updateTag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`product-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;isServerAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin price update&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nf"&gt;updateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`product-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;logInvalidation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;revalidateTag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;isServerAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin price update&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nf"&gt;revalidateTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Process-scoped.&lt;/strong&gt; Execution maps reset on cold start. In serverless environments each invocation may be a fresh process, so you will only see re-execution data within the same warm instance. For local dev with a long-running server it works exactly as intended.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best-effort concurrency.&lt;/strong&gt; Under concurrent rendering with identical args, both calls may log FIRST RUN rather than a miss. Detection does not affect correctness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cannot inspect Next.js internals.&lt;/strong&gt; The debugger counts executions to detect likely misses. It cannot read Next.js's internal cache store directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these affect production because the tool is not present there.&lt;/p&gt;

&lt;h2&gt;
  
  
  At a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What it detects&lt;/th&gt;
&lt;th&gt;Without this tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FIRST RUN / CACHE MISS / NEW KEY&lt;/td&gt;
&lt;td&gt;Not visible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic hole from short cacheLife&lt;/td&gt;
&lt;td&gt;Not visible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Missing cacheTag&lt;/td&gt;
&lt;td&gt;Not visible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deprecated revalidateTag&lt;/td&gt;
&lt;td&gt;TypeScript error, easy to miss&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;updateTag outside Server Action&lt;/td&gt;
&lt;td&gt;Runtime throw&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeated fetches in one render&lt;/td&gt;
&lt;td&gt;Not visible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Zero external dependencies. TypeScript 5.0+ with strict mode. Next.js 16 only -- &lt;code&gt;updateTag&lt;/code&gt; does not exist in Next.js 15. Double-gated on &lt;code&gt;NODE_ENV === 'development'&lt;/code&gt; AND &lt;code&gt;CACHE_DEBUG=true&lt;/code&gt; so nothing ships to production. No overhead, no bundle impact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get it
&lt;/h2&gt;

&lt;p&gt;Free forever, one &lt;code&gt;.tsx&lt;/code&gt; file: &lt;a href="https://shubhra.dev/snippets/nextjs-use-cache-debugger" rel="noopener noreferrer"&gt;shubhra.dev/snippets/nextjs-use-cache-debugger&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want the production enforcement layer that pairs with this -- type-safe tag registry, &lt;code&gt;safeRevalidate&lt;/code&gt; that blocks the deprecated single-arg call at compile time, &lt;code&gt;serverActionInvalidate&lt;/code&gt; that enforces the correct invalidation order -- that is the &lt;a href="https://shubhra.dev/snippets/nextjs-cache-pro" rel="noopener noreferrer"&gt;Cache Pro Kit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are new to the Next.js 16 caching model and want to understand what &lt;code&gt;'use cache'&lt;/code&gt;, &lt;code&gt;cacheLife&lt;/code&gt;, and &lt;code&gt;cacheTag&lt;/code&gt; are actually doing before using this toolkit, the &lt;a href="https://shubhra.dev/tutorials/nextjs-16-cache-components" rel="noopener noreferrer"&gt;practical migration guide&lt;/a&gt; covers the full picture. There is also a &lt;a href="https://shubhra.dev/quiz/nextjs-16-cache-components" rel="noopener noreferrer"&gt;15-question quiz&lt;/a&gt; if you want to test your understanding.&lt;/p&gt;

&lt;p&gt;If you are in the middle of a Next.js 16 caching migration and something is behaving unexpectedly, this will make it visible. What has been the most frustrating or confusing part of the new caching model for you?&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>Lighthouse Said It Was Fast. My Users Kept Clicking the Same Button.</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Wed, 06 May 2026 09:46:33 +0000</pubDate>
      <link>https://dev.to/shubhradev/lighthouse-said-it-was-fast-my-users-kept-clicking-the-same-button-4lng</link>
      <guid>https://dev.to/shubhradev/lighthouse-said-it-was-fast-my-users-kept-clicking-the-same-button-4lng</guid>
      <description>&lt;h2&gt;
  
  
  The bug wasn’t performance. It was silence.
&lt;/h2&gt;

&lt;p&gt;I ran into this while building a Next.js dashboard.&lt;/p&gt;

&lt;p&gt;There was a button that triggered a report generation flow. Some client-side processing, then an API call.&lt;/p&gt;

&lt;p&gt;Lighthouse looked great. API response was around 80ms.&lt;/p&gt;

&lt;p&gt;But session recordings told a different story.&lt;/p&gt;

&lt;p&gt;Users were clicking the button 3 to 5 times in a row.&lt;/p&gt;

&lt;p&gt;No errors in logs. No failed requests. Everything technically worked.&lt;/p&gt;

&lt;p&gt;So I watched one of the recordings more carefully.&lt;/p&gt;

&lt;p&gt;The moment the user clicked, nothing changed on screen.&lt;/p&gt;

&lt;p&gt;No loading state.&lt;br&gt;
No disabled button.&lt;br&gt;
No visual feedback at all.&lt;/p&gt;

&lt;p&gt;The UI looked exactly the same before and after the click.&lt;/p&gt;

&lt;p&gt;That was the issue.&lt;/p&gt;
&lt;h2&gt;
  
  
  80ms response, zero perceived response
&lt;/h2&gt;

&lt;p&gt;The backend was fast.&lt;/p&gt;

&lt;p&gt;The interface just didn’t acknowledge the interaction.&lt;/p&gt;

&lt;p&gt;From the user’s point of view, the click didn’t go through.&lt;/p&gt;

&lt;p&gt;So they clicked again.&lt;/p&gt;

&lt;p&gt;And again.&lt;/p&gt;

&lt;p&gt;Not because they were impatient. Because the UI stayed silent.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where most of us focus (and where it falls short)
&lt;/h2&gt;

&lt;p&gt;We spend a lot of time optimizing load performance.&lt;/p&gt;

&lt;p&gt;FCP, LCP, bundle size, Lighthouse scores. All worth caring about.&lt;/p&gt;

&lt;p&gt;But most of the time a user spends on your app happens after the page has loaded.&lt;/p&gt;

&lt;p&gt;That’s where trust is decided. In the interactions.&lt;/p&gt;
&lt;h2&gt;
  
  
  The 200ms line
&lt;/h2&gt;

&lt;p&gt;There’s a threshold that shows up consistently in real usage.&lt;/p&gt;

&lt;p&gt;If the UI responds within roughly 100 to 200ms, it feels instant.&lt;/p&gt;

&lt;p&gt;Between 200 and 500ms, the delay becomes noticeable.&lt;/p&gt;

&lt;p&gt;Beyond that, people start questioning whether their action worked.&lt;/p&gt;

&lt;p&gt;A slow app is frustrating. An app that feels unresponsive gets abandoned.&lt;/p&gt;
&lt;h2&gt;
  
  
  What INP actually measures
&lt;/h2&gt;

&lt;p&gt;INP (Interaction to Next Paint) focuses on one thing:&lt;/p&gt;

&lt;p&gt;How long it takes for the user to &lt;em&gt;see&lt;/em&gt; a response after they interact.&lt;/p&gt;

&lt;p&gt;Not when your API returns.&lt;br&gt;
Not when your function finishes.&lt;/p&gt;

&lt;p&gt;When something visibly changes on the screen.&lt;/p&gt;

&lt;p&gt;That’s what closes the loop.&lt;/p&gt;
&lt;h2&gt;
  
  
  The fix was not “make it faster”
&lt;/h2&gt;

&lt;p&gt;The fix was: acknowledge the interaction immediately.&lt;/p&gt;

&lt;p&gt;Instead of doing all the work first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;processData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;syncWithServer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flip it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// immediate visual feedback&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// let the browser paint&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;processData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;scheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;syncWithServer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;scheduler.yield()&lt;/code&gt; is not available yet in your environment, a simple fallback works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yieldToMain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same total work. Same total time.&lt;/p&gt;

&lt;p&gt;Completely different experience.&lt;/p&gt;

&lt;p&gt;Users stopped clicking multiple times.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern you already use
&lt;/h2&gt;

&lt;p&gt;You’ve seen this in every modern app.&lt;/p&gt;

&lt;p&gt;You tap like. It updates instantly. The server confirms later.&lt;/p&gt;

&lt;p&gt;That’s optimistic UI.&lt;/p&gt;

&lt;p&gt;Here is the same idea in a simple form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleLike&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setLiked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setLiked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In React and Next.js setups, this maps cleanly to &lt;code&gt;useOptimistic&lt;/code&gt; and Server Actions.&lt;/p&gt;

&lt;p&gt;The idea stays the same:&lt;/p&gt;

&lt;p&gt;Show the result immediately. Reconcile in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters more than Lighthouse 100
&lt;/h2&gt;

&lt;p&gt;Lighthouse runs in controlled conditions.&lt;/p&gt;

&lt;p&gt;Your users don’t.&lt;/p&gt;

&lt;p&gt;They’re on slower devices, switching tabs, running background apps, dealing with network jitter.&lt;/p&gt;

&lt;p&gt;You can ship a perfect score and still have interactions that feel off.&lt;/p&gt;

&lt;p&gt;INP exposes that gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to go deeper
&lt;/h2&gt;

&lt;p&gt;This bug was the entry point for me.&lt;/p&gt;

&lt;p&gt;I ended up breaking this down properly across INP, optimistic UI, task yielding, and how this fits into modern Next.js setups like Server Actions and streaming.&lt;/p&gt;

&lt;p&gt;I wrote it up in detail here:&lt;br&gt;
&lt;a href="https://shubhra.dev/tutorials/performance-first-ui-mastery-guide-2026" rel="noopener noreferrer"&gt;https://shubhra.dev/tutorials/performance-first-ui-mastery-guide-2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That one goes deeper into how to actually implement this in real apps. This post is just the moment where the problem becomes obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick way to test this
&lt;/h2&gt;

&lt;p&gt;While working through this, I built a small quiz to check if I actually understood the idea or was just agreeing with it.&lt;/p&gt;

&lt;p&gt;Here’s one of the questions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A user clicks a button.&lt;br&gt;
The server responds in 80ms.&lt;br&gt;
They click four more times.&lt;/p&gt;

&lt;p&gt;What actually failed?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most people still go to backend performance first.&lt;/p&gt;

&lt;p&gt;If that was your instinct too, you’ll probably find the rest useful:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://shubhra.dev/quiz/performance-first-ui" rel="noopener noreferrer"&gt;https://shubhra.dev/quiz/performance-first-ui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s short. Focused on real interaction problems. No trick questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  One practical takeaway
&lt;/h2&gt;

&lt;p&gt;Next time you write a click handler, check the order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does something change on screen immediately?&lt;/li&gt;
&lt;li&gt;Or does all the work happen before the user sees anything?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That one decision is often the difference between a UI that feels fast and one that feels broken.&lt;/p&gt;

&lt;p&gt;If you’ve run into this in your own apps, I’m curious what caused it and how you approached it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>nextjs</category>
      <category>react</category>
    </item>
    <item>
      <title>Why Most React Infinite Scroll Hooks Fail in Production (and the One That Fixed It for Me)</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Thu, 30 Apr 2026 11:28:52 +0000</pubDate>
      <link>https://dev.to/shubhradev/why-most-react-infinite-scroll-hooks-fail-in-production-and-the-one-that-fixed-it-for-me-moa</link>
      <guid>https://dev.to/shubhradev/why-most-react-infinite-scroll-hooks-fail-in-production-and-the-one-that-fixed-it-for-me-moa</guid>
      <description>&lt;p&gt;I used to believe infinite scroll was one of the simplest features to implement.&lt;/p&gt;

&lt;p&gt;Fetch data → append to a list → load more on scroll.&lt;/p&gt;

&lt;p&gt;Easy, right?&lt;/p&gt;

&lt;p&gt;That’s exactly how most tutorials show it.&lt;/p&gt;

&lt;p&gt;And honestly… it works.&lt;/p&gt;

&lt;p&gt;Until it doesn’t.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bug That Changed Everything
&lt;/h2&gt;

&lt;p&gt;One bug completely changed how I think about infinite scroll.&lt;/p&gt;

&lt;p&gt;A user changed a filter → the list reset → new data loaded.&lt;/p&gt;

&lt;p&gt;Everything looked correct.&lt;/p&gt;

&lt;p&gt;Then a couple of seconds later…&lt;/p&gt;

&lt;p&gt;the old results came back and overwrote the new ones.&lt;/p&gt;

&lt;p&gt;No errors. No warnings.&lt;/p&gt;

&lt;p&gt;Just silently broken UI.&lt;/p&gt;

&lt;p&gt;What actually happened?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A slow request from the previous state finished late and updated the UI with stale data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was the moment I realized:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Infinite scroll doesn’t break in demos.It breaks with real users, real timing, and real networks.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Things Start Falling Apart
&lt;/h2&gt;

&lt;p&gt;After that, I started noticing the same issues again and again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stale requests overwriting fresh data after reset&lt;/li&gt;
&lt;li&gt;Retry logic fetching the wrong page&lt;/li&gt;
&lt;li&gt;IntersectionObserver continuing to fire after errors&lt;/li&gt;
&lt;li&gt;Duplicate requests in React Strict Mode&lt;/li&gt;
&lt;li&gt;Loading states that never resolve&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These problems rarely show up locally.&lt;/p&gt;

&lt;p&gt;But in production, they show up fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Actually Needed
&lt;/h2&gt;

&lt;p&gt;Not another demo.&lt;/p&gt;

&lt;p&gt;Something I could trust in a real app.&lt;/p&gt;

&lt;p&gt;So I built a hook around one idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Control the async flow. Don’t just “load more data”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What This Hook Handles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✔ Cancels stale requests (no overwrite bugs)&lt;/li&gt;
&lt;li&gt;✔ Smart retry logic (correct page every time)&lt;/li&gt;
&lt;li&gt;✔ Proper observer cleanup (no leaks)&lt;/li&gt;
&lt;li&gt;✔ React 18+ Strict Mode safe&lt;/li&gt;
&lt;li&gt;✔ Clear initial vs pagination loading states&lt;/li&gt;
&lt;li&gt;✔ Manual &lt;code&gt;loadMore&lt;/code&gt;, &lt;code&gt;reset&lt;/code&gt;, and &lt;code&gt;retry&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✔ Zero dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic Usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isInitialLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;hasMore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;loadMoreRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;reset&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useInfiniteScroll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;fetchFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/posts?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Sentinel element */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loadMoreRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;retry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Retry&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real Use Case: Reset on Filter Change
&lt;/h2&gt;

&lt;p&gt;This is where most bugs happen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// cancels old request + reloads safely&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without proper handling, this is exactly where stale data bugs appear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AbortController Matters So Much
&lt;/h2&gt;

&lt;p&gt;Before using it:&lt;/p&gt;

&lt;p&gt;old requests still resolved&lt;br&gt;
stale data overwrote the UI&lt;/p&gt;

&lt;p&gt;After using it:&lt;/p&gt;

&lt;p&gt;old requests get cancelled immediately&lt;br&gt;
they never reach your state&lt;/p&gt;

&lt;p&gt;That single change removes an entire class of bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Honest Note
&lt;/h2&gt;

&lt;p&gt;This hook handles most real-world issues.&lt;/p&gt;

&lt;p&gt;But for very large lists, you should still use virtualization&lt;br&gt;
(like react-window or tanstack/virtual).&lt;/p&gt;

&lt;p&gt;Infinite scroll solves loading.&lt;/p&gt;

&lt;p&gt;Virtualization solves rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;You can grab the full hook here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://shubhra.dev/snippets/use-infinite-scroll" rel="noopener noreferrer"&gt;https://shubhra.dev/snippets/use-infinite-scroll&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MIT licensed&lt;br&gt;
free to copy and modify&lt;br&gt;
built for real production cases&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;I didn’t build this because infinite scroll is hard.&lt;/p&gt;

&lt;p&gt;I built it because the small edge cases are what break real products.&lt;/p&gt;

&lt;p&gt;Slow APIs. Fast users. Overlapping requests.&lt;/p&gt;

&lt;p&gt;That’s where things actually fall apart.&lt;/p&gt;

&lt;p&gt;Curious - what broke for you?&lt;/p&gt;

&lt;p&gt;Have you ever hit a weird infinite scroll bug in production?&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;duplicate data&lt;/li&gt;
&lt;li&gt;stale UI&lt;/li&gt;
&lt;li&gt;loading that never stops&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Would genuinely love to hear what you ran into.&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Turned My Blog Into a Full Developer Platform (Tutorials + Snippets + Quizzes + Tools)</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Tue, 28 Apr 2026 12:25:37 +0000</pubDate>
      <link>https://dev.to/shubhradev/i-turned-my-blog-into-a-full-developer-platform-tutorials-snippets-quizzes-tools-2jd7</link>
      <guid>https://dev.to/shubhradev/i-turned-my-blog-into-a-full-developer-platform-tutorials-snippets-quizzes-tools-2jd7</guid>
      <description>&lt;p&gt;I’ve been working on building a developer platform with tutorials, reusable code snippets, interactive quizzes, and practical tools. This post shares what changed and what I’m building now.&lt;/p&gt;

&lt;p&gt;For the past few months, I’ve been a little quiet here.&lt;/p&gt;

&lt;p&gt;If you’ve been active on Dev.to regularly, you probably noticed I wasn’t reading as many posts, commenting, or sharing like I used to. And honestly, I missed that.&lt;/p&gt;

&lt;p&gt;This community has always been one of my favorite places to learn and grow. Reading how others think, build, and solve problems has helped me a lot in my own journey.&lt;/p&gt;

&lt;p&gt;So stepping away from that wasn’t easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Went Quiet
&lt;/h2&gt;

&lt;p&gt;I reached a point where I felt like just writing blog posts wasn’t enough for me anymore.&lt;/p&gt;

&lt;p&gt;Don’t get me wrong, I still love writing. But I kept thinking:&lt;/p&gt;

&lt;p&gt;What if I could make something more useful than just articles?&lt;/p&gt;

&lt;p&gt;Something that helps people not only read, but also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;try things quickly
&lt;/li&gt;
&lt;li&gt;test their understanding
&lt;/li&gt;
&lt;li&gt;and actually use code in real projects
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That idea stayed in my mind for a while.&lt;/p&gt;

&lt;p&gt;And instead of talking about it, I decided to just build it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I’ve Been Working On
&lt;/h2&gt;

&lt;p&gt;I took my simple blog and slowly turned it into something more complete.&lt;/p&gt;

&lt;p&gt;Now it’s not just posts. It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tutorials that go step by step
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s how one of the tutorials looks:&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Small, practical code snippets you can directly use
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A quick example of a reusable snippet in action:&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Quizzes to test concepts in a quick way
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a quick look at how the quiz works:&lt;/p&gt;

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

&lt;p&gt;Here’s a small taste of what the quizzes look like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. What does the &lt;code&gt;===&lt;/code&gt; operator do?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checks for value equality only
&lt;/li&gt;
&lt;li&gt;Checks for reference equality only
&lt;/li&gt;
&lt;li&gt;Checks for both value and type equality without coercion
&lt;/li&gt;
&lt;li&gt;Assigns a value
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ Correct answer: Checks for both value and type equality without coercion  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What is a closure in JavaScript?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A way to immediately end a function
&lt;/li&gt;
&lt;li&gt;A function that retains access to its outer scope
&lt;/li&gt;
&lt;li&gt;A syntax error
&lt;/li&gt;
&lt;li&gt;A loop
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ Correct answer: A function that retains access to its outer scope  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What will &lt;code&gt;typeof null&lt;/code&gt; return?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;'null'
&lt;/li&gt;
&lt;li&gt;'undefined'
&lt;/li&gt;
&lt;li&gt;'object'
&lt;/li&gt;
&lt;li&gt;'number'
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ Correct answer: 'object'  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A couple of products built from things I personally needed
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s still growing, still improving, and definitely not perfect.&lt;/p&gt;

&lt;p&gt;But it feels closer to what I actually wanted to create.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed for Me
&lt;/h2&gt;

&lt;p&gt;Earlier, I was mostly focused on sharing information.&lt;/p&gt;

&lt;p&gt;Now I’m trying to focus more on usefulness.&lt;/p&gt;

&lt;p&gt;Instead of just explaining things, I want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;make it easier to apply them
&lt;/li&gt;
&lt;li&gt;keep things simple and practical
&lt;/li&gt;
&lt;li&gt;and help someone save time when they’re stuck
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even the smallest snippet can be helpful if it solves a real problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Missed This Community
&lt;/h2&gt;

&lt;p&gt;One thing I realized during this time is how much I value this space.&lt;/p&gt;

&lt;p&gt;Reading posts here, seeing different approaches, and learning from others is something I genuinely enjoy.&lt;/p&gt;

&lt;p&gt;I missed that part.&lt;/p&gt;

&lt;p&gt;So I’m coming back, not just to share, but also to read, learn, and engage again.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You’ll See From Me Now
&lt;/h2&gt;

&lt;p&gt;I’ll start sharing more regularly again, but with a slightly different approach.&lt;/p&gt;

&lt;p&gt;You’ll see things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;small useful snippets
&lt;/li&gt;
&lt;li&gt;short explanations
&lt;/li&gt;
&lt;li&gt;occasional deep tutorials
&lt;/li&gt;
&lt;li&gt;and some interesting questions or quizzes
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing too heavy. Just practical and helpful.&lt;/p&gt;

&lt;h2&gt;
  
  
  If You Want to Check What I Built
&lt;/h2&gt;

&lt;p&gt;Here’s how everything comes together:&lt;/p&gt;

&lt;p&gt;If you’re curious, you can take a look here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://shubhra.dev/" rel="noopener noreferrer"&gt;https://shubhra.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No pressure at all. Just sharing what I’ve been working on.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Small Thought
&lt;/h2&gt;

&lt;p&gt;Sometimes we feel like we need to keep posting consistently no matter what.&lt;/p&gt;

&lt;p&gt;But taking a step back to build something meaningful can be just as important.&lt;/p&gt;

&lt;p&gt;For me, this phase helped me rethink what I actually want to create and share.&lt;/p&gt;

&lt;p&gt;And I’m glad I took that time.&lt;/p&gt;

&lt;p&gt;I’m looking forward to reading your posts again and being more active here.&lt;/p&gt;

&lt;p&gt;If you’ve been working on something quietly too, I’d love to hear about it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>fullstack</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Performance First UI Taught Me More Than Any Framework Ever Did</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Mon, 12 Jan 2026 10:40:43 +0000</pubDate>
      <link>https://dev.to/shubhradev/performance-first-ui-taught-me-more-than-any-framework-ever-did-3c0d</link>
      <guid>https://dev.to/shubhradev/performance-first-ui-taught-me-more-than-any-framework-ever-did-3c0d</guid>
      <description>&lt;p&gt;The slowest app I ever worked on had a perfect performance score.&lt;br&gt;&lt;br&gt;
That sentence used to confuse me.&lt;br&gt;&lt;br&gt;
Everything was optimized. Bundles were trimmed. Images were compressed. Lighthouse smiled back at me like a proud teacher.  &lt;/p&gt;

&lt;p&gt;And yet, users kept behaving strangely.&lt;br&gt;&lt;br&gt;
They clicked twice.&lt;br&gt;&lt;br&gt;
They hesitated.&lt;br&gt;&lt;br&gt;
They abandoned flows halfway through.  &lt;/p&gt;

&lt;p&gt;At first, I blamed users. Then devices. Then networks.&lt;br&gt;&lt;br&gt;
Eventually, I blamed myself.&lt;br&gt;&lt;br&gt;
That was the moment I started understanding &lt;strong&gt;performance first UI&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed is not what developers think it is
&lt;/h2&gt;

&lt;p&gt;As developers, we grow up believing speed is a number.&lt;br&gt;&lt;br&gt;
Milliseconds.&lt;br&gt;&lt;br&gt;
Scores.&lt;br&gt;&lt;br&gt;
Graphs.  &lt;/p&gt;

&lt;p&gt;But users never see numbers. They feel moments.&lt;br&gt;&lt;br&gt;
The moment after a click.&lt;br&gt;&lt;br&gt;
The moment after a tap.&lt;br&gt;&lt;br&gt;
The moment when they expect acknowledgment.  &lt;/p&gt;

&lt;p&gt;If nothing happens in that moment, something breaks not technically, but emotionally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The day I stopped trusting Lighthouse alone
&lt;/h2&gt;

&lt;p&gt;Lighthouse is useful. It taught an entire generation to care about performance.&lt;br&gt;&lt;br&gt;
But in 2026, relying on Lighthouse alone is like judging a car by how fast it accelerates on an empty track.  &lt;/p&gt;

&lt;p&gt;Real users drive in traffic.&lt;br&gt;&lt;br&gt;
They scroll while data loads.&lt;br&gt;&lt;br&gt;
They click while JavaScript executes.&lt;br&gt;&lt;br&gt;
They type while hydration finishes.  &lt;/p&gt;

&lt;p&gt;That’s where performance first UI lives, not at load time, but during interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interaction is the real contract with the user
&lt;/h2&gt;

&lt;p&gt;A page load is an introduction.&lt;br&gt;&lt;br&gt;
An interaction is a promise.  &lt;/p&gt;

&lt;p&gt;When a user clicks a button, they are not asking for data. They are asking for reassurance.&lt;br&gt;&lt;br&gt;
&lt;em&gt;Did you hear me?&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Are you working?&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Can I trust you?&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;If your interface stays visually silent, the promise is broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Interaction to Next Paint quietly changed everything
&lt;/h2&gt;

&lt;p&gt;Interaction to Next Paint does something rare in web metrics.&lt;br&gt;&lt;br&gt;
It measures reality.  &lt;/p&gt;

&lt;p&gt;Not when logic finishes.&lt;br&gt;&lt;br&gt;
Not when promises resolve.&lt;br&gt;&lt;br&gt;
But when pixels change.  &lt;/p&gt;

&lt;p&gt;This sounds obvious, but it reframes how you write UI code.&lt;br&gt;&lt;br&gt;
Because suddenly, doing work before paint feels dangerous.  &lt;/p&gt;

&lt;p&gt;If this shift in thinking around Interaction to Next Paint resonated with you, I’ve explored it in much more depth in my long-form guide &lt;em&gt;&lt;a href="https://blog.shubhra.dev/performance-first-ui-mastery-guide-2026/" rel="noopener noreferrer"&gt;Performance First UI Mastery: A Critical Guide for 2026 Developers&lt;/a&gt;&lt;/em&gt;, where I break down real-world examples, beginner-to-advanced concepts, and how this mindset plays out in modern Next.js apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hidden enemy of modern interfaces
&lt;/h2&gt;

&lt;p&gt;Most INP problems are not caused by slow servers.&lt;br&gt;&lt;br&gt;
They are caused by good intentions.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Too much logic inside event handlers
&lt;/li&gt;
&lt;li&gt;Too many state updates
&lt;/li&gt;
&lt;li&gt;Too many components reacting at once
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything works. Everything is correct. Everything is just slightly late.&lt;br&gt;&lt;br&gt;
And that slight lateness compounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The small habit that fixed most of my issues
&lt;/h2&gt;

&lt;p&gt;The biggest improvement I ever made to interaction performance was embarrassingly simple.&lt;br&gt;&lt;br&gt;
I stopped doing real work before showing feedback.  &lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Click → compute → update UI&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;I switched to:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Click → update UI → compute&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Nothing fancy. No new libraries.&lt;br&gt;&lt;br&gt;
Just respect for the paint cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why modern Next.js makes this mindset possible
&lt;/h2&gt;

&lt;p&gt;Next.js quietly evolved alongside performance first UI thinking.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partial Prerendering lets interfaces appear ready before they are complete.
&lt;/li&gt;
&lt;li&gt;Streaming lets content arrive without blocking interaction.
&lt;/li&gt;
&lt;li&gt;Server Actions let the UI move first and confirm later.
&lt;/li&gt;
&lt;li&gt;Edge Middleware removes entire decision trees from the client.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Used correctly, these tools keep the browser free to respond.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance is not about doing less, it’s about doing things later
&lt;/h2&gt;

&lt;p&gt;This was a hard lesson for me.&lt;br&gt;&lt;br&gt;
I used to chase minimalism. Fewer features. Smaller bundles.  &lt;/p&gt;

&lt;p&gt;But performance first UI taught me something better.&lt;br&gt;&lt;br&gt;
You can do a lot, just not all at once.  &lt;/p&gt;

&lt;p&gt;Defer what the user cannot see.&lt;br&gt;&lt;br&gt;
Delay what the user does not care about yet.&lt;br&gt;&lt;br&gt;
Focus on what the user just did.&lt;/p&gt;

&lt;h2&gt;
  
  
  The business side developers rarely talk about
&lt;/h2&gt;

&lt;p&gt;Here’s an uncomfortable truth.&lt;br&gt;&lt;br&gt;
A sluggish interaction costs more than a slow page load.  &lt;/p&gt;

&lt;p&gt;Because interaction delay happens when the user is already invested.&lt;br&gt;&lt;br&gt;
They clicked.&lt;br&gt;&lt;br&gt;
They intended.&lt;br&gt;&lt;br&gt;
They were ready.  &lt;/p&gt;

&lt;p&gt;Losing them here hurts conversion far more than a slow landing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance is becoming a human skill again
&lt;/h2&gt;

&lt;p&gt;In 2026, AI can generate components.&lt;br&gt;&lt;br&gt;
AI can refactor code.&lt;br&gt;&lt;br&gt;
AI can optimize assets.  &lt;/p&gt;

&lt;p&gt;But AI cannot feel hesitation.&lt;br&gt;&lt;br&gt;
It cannot sense when a transition feels awkward.&lt;br&gt;&lt;br&gt;
It cannot sense when feedback arrives too late.  &lt;/p&gt;

&lt;p&gt;That sensitivity is now the developer’s real value.&lt;/p&gt;

&lt;h2&gt;
  
  
  What performance first UI actually demands from us
&lt;/h2&gt;

&lt;p&gt;It demands patience.&lt;br&gt;&lt;br&gt;
It demands that we observe our own interfaces instead of trusting dashboards.&lt;br&gt;&lt;br&gt;
It demands that we click our own buttons slowly and ask:  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Does this feel respectful?&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Not impressive.&lt;br&gt;&lt;br&gt;
Not clever.&lt;br&gt;&lt;br&gt;
Respectful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;Performance first UI is not a trend. It is a correction.&lt;br&gt;&lt;br&gt;
A return to building software that listens.  &lt;/p&gt;

&lt;p&gt;If your UI responds instantly, users forgive imperfections.&lt;br&gt;&lt;br&gt;
If it hesitates, they remember.  &lt;/p&gt;

&lt;p&gt;In the end, performance is not about speed.&lt;br&gt;&lt;br&gt;
It is about trust.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>webperf</category>
      <category>ux</category>
      <category>inp</category>
    </item>
    <item>
      <title>How CSS Animation Helped Me Build Interfaces That Feel Alive</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Mon, 22 Dec 2025 06:24:42 +0000</pubDate>
      <link>https://dev.to/shubhradev/how-css-animation-helped-me-build-interfaces-that-feel-alive-9pb</link>
      <guid>https://dev.to/shubhradev/how-css-animation-helped-me-build-interfaces-that-feel-alive-9pb</guid>
      <description>&lt;p&gt;I always believed great UI was about color, spacing, structure, and typography. I spent years improving those things. I obsessed over grids. I experimented with type scales. I rewrote layout systems again and again.&lt;br&gt;&lt;br&gt;
Yet something still felt missing.&lt;/p&gt;

&lt;p&gt;Every interface I created worked perfectly, but emotionally it felt silent. It behaved like a machine. Nothing moved unless a page refreshed. Nothing acknowledged the user. I did not realize how empty that silence was until I compared my projects with modern interfaces around the web.&lt;/p&gt;

&lt;p&gt;Some apps felt warm and alive, even though their layouts were simple. Their buttons breathed. Their cards shifted gently when hovered. Even status messages faded in and out like they had personality.&lt;/p&gt;

&lt;p&gt;I kept asking myself&lt;br&gt;&lt;br&gt;
How are they doing that?&lt;/p&gt;

&lt;p&gt;That question pushed me toward CSS Animation.&lt;br&gt;&lt;br&gt;
Not as a design trend&lt;br&gt;
but as a missing piece of expression.&lt;/p&gt;

&lt;h2&gt;
  
  
  My First Real Encounter With Motion
&lt;/h2&gt;

&lt;p&gt;My turning point arrived inside a dashboard project. Everything looked clean and minimal. The data tables worked. The navigation was solid. The code was tidy.&lt;br&gt;&lt;br&gt;
But the experience lacked a pulse.&lt;/p&gt;

&lt;p&gt;One evening while polishing the UI, I decided to animate only a single button. Not to impress anyone, but to understand how it would feel. I added a soft hover lift and a clearer color transition. Nothing dramatic.&lt;/p&gt;

&lt;p&gt;The moment I refreshed the browser&lt;br&gt;
the UI reacted like it suddenly woke up.&lt;br&gt;&lt;br&gt;
The button rose slightly.&lt;br&gt;&lt;br&gt;
The shadow deepened.&lt;br&gt;&lt;br&gt;
It felt like the interface acknowledged me.&lt;/p&gt;

&lt;p&gt;It was such a small change that the code barely filled a few lines, and yet the product felt more professional instantly.&lt;br&gt;&lt;br&gt;
That tiny success completely changed how I saw CSS Animation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Motion Matters To Users
&lt;/h2&gt;

&lt;p&gt;Modern users expect movement even if they cannot explain why.&lt;br&gt;&lt;br&gt;
Motion tells the brain something is happening.&lt;br&gt;&lt;br&gt;
It guides attention with subtle cues.&lt;br&gt;&lt;br&gt;
It communicates structure faster than text.&lt;/p&gt;

&lt;p&gt;When a button lifts&lt;br&gt;
you know it is clickable.&lt;br&gt;&lt;br&gt;
When content fades gently&lt;br&gt;
you understand that something changed without reading anything.  &lt;/p&gt;

&lt;p&gt;Motion replaces confusion with instinct.&lt;/p&gt;

&lt;p&gt;Once I understood that, I saw animation everywhere:&lt;br&gt;&lt;br&gt;
apps, websites, mobile UI, operating systems, ecommerce stores.  &lt;/p&gt;

&lt;p&gt;Motion has become the language of modern interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS Animation Is Not Just Decoration
&lt;/h2&gt;

&lt;p&gt;Before learning it deeply, I believed animation was fancy.&lt;br&gt;&lt;br&gt;
I assumed it slowed pages down.&lt;br&gt;&lt;br&gt;
I thought it was extra work for no real benefit.&lt;br&gt;&lt;br&gt;
All of that was wrong.&lt;/p&gt;

&lt;p&gt;CSS Animation can improve usability in extremely practical ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Guiding users to the next step
&lt;/li&gt;
&lt;li&gt;Confirming they clicked something
&lt;/li&gt;
&lt;li&gt;Building visual rhythm
&lt;/li&gt;
&lt;li&gt;Reducing visual shock
&lt;/li&gt;
&lt;li&gt;Improving brand identity
&lt;/li&gt;
&lt;li&gt;Creating focus without clutter
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Motion is not frosting on top of UI. It is part of UI itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mindset Shift That Helped Me Learn Faster
&lt;/h2&gt;

&lt;p&gt;The biggest challenge was learning how to think about motion.&lt;/p&gt;

&lt;p&gt;I stopped asking &lt;em&gt;How do I make this look cool?&lt;/em&gt;&lt;br&gt;&lt;br&gt;
and started asking &lt;em&gt;What should the user feel here?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When they open a page, maybe they should feel welcomed.&lt;br&gt;&lt;br&gt;
When they press save, maybe they should feel confirmed.&lt;br&gt;&lt;br&gt;
When they hover over content, maybe they should feel engaged.  &lt;/p&gt;

&lt;p&gt;That mindset turned animation into storytelling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CSS Animation Works So Well With Modern UI
&lt;/h2&gt;

&lt;p&gt;CSS Animation is not heavy, nor complicated, nor dependent on JavaScript.&lt;br&gt;&lt;br&gt;
It is built to run smoothly if you animate the right properties.&lt;/p&gt;

&lt;p&gt;Transforms and opacity create GPU-powered motion that feels fluid even on average devices.  &lt;/p&gt;

&lt;p&gt;The more I practiced, the more confident I became because I saw that animation can stay clean and fast when done with purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Surprising Part
&lt;/h2&gt;

&lt;p&gt;Clients noticed the improvements immediately.&lt;br&gt;&lt;br&gt;
They could not describe what changed in technical language,&lt;br&gt;&lt;br&gt;
but they kept saying the same thing -&lt;br&gt;
"This feels better.",&lt;/p&gt;

&lt;p&gt;Not &lt;em&gt;This looks better&lt;/em&gt;, but &lt;em&gt;This feels better.&lt;/em&gt;&lt;br&gt;
That sentence taught me something powerful:&lt;br&gt;&lt;br&gt;
Users care about feeling, not code.&lt;/p&gt;

&lt;h2&gt;
  
  
  A New Way Of Seeing My Projects
&lt;/h2&gt;

&lt;p&gt;Today I build interfaces very differently.&lt;br&gt;&lt;br&gt;
I do not start by applying motion everywhere.&lt;br&gt;&lt;br&gt;
I begin by searching for moments where the UI speaks to users.&lt;br&gt;
Moments that deserve attention, and moments that need softness.  &lt;/p&gt;

&lt;p&gt;Sometimes it is a card hover.&lt;br&gt;&lt;br&gt;
Sometimes it is a hero title reveal.&lt;br&gt;&lt;br&gt;
Sometimes it is a form success message.  &lt;/p&gt;

&lt;p&gt;Motion is now part of my design decisions, not an afterthought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want To Learn How I Apply CSS Animation To Real UI
&lt;/h2&gt;

&lt;p&gt;I recently wrote a deep story and breakdown on my blog showing how CSS Animation reshaped my understanding of UI feeling and movement.&lt;br&gt;&lt;br&gt;
You can read it here:&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://blog.shubhra.dev/css-animation-level-up-ui" rel="noopener noreferrer"&gt;https://blog.shubhra.dev/css-animation-level-up-ui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are a developer who wants your UI to feel more human, this will help you see animation differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;The moment you experience your first animated interaction that feels natural, not flashy, you understand why motion matters.&lt;br&gt;&lt;br&gt;
CSS Animation is not only a visual tool, it is emotional design.&lt;br&gt;&lt;br&gt;
And once you learn it, you never see UI the same way again.&lt;/p&gt;

</description>
      <category>css</category>
      <category>animation</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>The CSS Positioning Chaos: Why Your Elements Run Away (And How I Finally Mastered the 5 Keys)</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Fri, 28 Nov 2025 07:54:55 +0000</pubDate>
      <link>https://dev.to/shubhradev/the-css-positioning-chaos-why-your-elements-run-away-and-how-i-finally-mastered-the-5-keys-4apb</link>
      <guid>https://dev.to/shubhradev/the-css-positioning-chaos-why-your-elements-run-away-and-how-i-finally-mastered-the-5-keys-4apb</guid>
      <description>&lt;p&gt;There is a special kind of chaos that only frontend developers understand.&lt;br&gt;&lt;br&gt;
The kind where your layout looks perfect one second and then suddenly one button escapes to the top corner of the screen like it has its own dreams and ambitions.&lt;/p&gt;

&lt;p&gt;That chaos usually has a name: &lt;strong&gt;CSS Positioning&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Every developer goes through this phase.&lt;br&gt;&lt;br&gt;
Every beginner gets confused.  &lt;/p&gt;

&lt;p&gt;And honestly, even after years of working with CSS, I still smile whenever someone asks me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Why does my element move when I scroll?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because that question reminds me of my own journey, a journey full of tiny mistakes, confused evenings, and small victories that made CSS feel less like a puzzle and more like a friend.&lt;/p&gt;

&lt;p&gt;Recently, I wrote a full blog post on my main site where I broke down CSS Positioning in the simplest, most practical way I could.&lt;br&gt;&lt;br&gt;
Today I wanted to share a little behind the scenes of that post and also explain why CSS Positioning deserves more love than it gets.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Phase Where CSS Positioning Made Me Doubt My Career Choices
&lt;/h2&gt;

&lt;p&gt;Let me tell you something honestly.&lt;/p&gt;

&lt;p&gt;In my early days of coding, nothing confused me more than &lt;strong&gt;absolute&lt;/strong&gt; and &lt;strong&gt;relative&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
I remember placing a badge inside a hero section and the moment I refreshed the page, it flew somewhere completely unrelated.&lt;br&gt;&lt;br&gt;
I thought I broke the browser. I even restarted my laptop once thinking something was wrong with VS Code.&lt;/p&gt;

&lt;p&gt;Little did I know it was just CSS Positioning doing its usual drama.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;static&lt;/code&gt; was too simple
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;relative&lt;/code&gt; felt too subtle
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;absolute&lt;/code&gt; felt too free
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fixed&lt;/code&gt; felt too stubborn
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sticky&lt;/code&gt; felt like magic
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And because I did not understand their personalities, I kept fighting them instead of letting them help me.&lt;/p&gt;

&lt;p&gt;It took me weeks to finally understand that CSS Positioning is not just about moving elements around.&lt;br&gt;&lt;br&gt;
It is about understanding how the browser thinks.&lt;br&gt;&lt;br&gt;
How it calculates boundaries.&lt;br&gt;&lt;br&gt;
How it decides the &lt;strong&gt;containing block&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
How each element follows a very logical set of rules.&lt;/p&gt;

&lt;p&gt;Once I understood this, the fear disappeared.&lt;br&gt;&lt;br&gt;
And CSS started feeling like a superpower.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Beauty Behind Understanding CSS Positioning
&lt;/h2&gt;

&lt;p&gt;When you truly understand CSS Positioning, you begin to see your layout differently.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static&lt;/strong&gt; becomes your calm baseline.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relative&lt;/strong&gt; becomes your gentle adjustment tool.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Absolute&lt;/strong&gt; becomes the creative freedom you use when you want elements to float exactly where you want.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed&lt;/strong&gt; becomes your loyal companion for floating buttons and sticky helpers.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sticky&lt;/strong&gt; becomes the modern magic that makes long pages feel smoother.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The moment you master these five:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your designs stop breaking
&lt;/li&gt;
&lt;li&gt;your elements stop running away
&lt;/li&gt;
&lt;li&gt;and your confidence grows instantly
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why CSS Positioning is not just a “topic” — it is a core foundation that every modern frontend layout quietly depends on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Best Way To Learn CSS Positioning Is Not Memorizing It
&lt;/h2&gt;

&lt;p&gt;One of the main things I shared in my WordPress post is something simple but important:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS Positioning is not learned through memorization.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It is learned through &lt;strong&gt;experience&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You learn it by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;building small boxes
&lt;/li&gt;
&lt;li&gt;adding a badge
&lt;/li&gt;
&lt;li&gt;scrolling a page
&lt;/li&gt;
&lt;li&gt;trying &lt;code&gt;absolute&lt;/code&gt; without &lt;code&gt;relative&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;trying &lt;code&gt;sticky&lt;/code&gt; inside a tiny container
&lt;/li&gt;
&lt;li&gt;placing a button with &lt;code&gt;fixed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;and observing every single behavior
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This hands‑on curiosity is what transforms CSS Positioning from confusing to intuitive.&lt;br&gt;&lt;br&gt;
And once it clicks, you will wonder how you ever struggled with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Topic Deserves More Attention
&lt;/h2&gt;

&lt;p&gt;We often jump directly into Flexbox, Grid, animations, Tailwind, frameworks, and component libraries.&lt;br&gt;&lt;br&gt;
But behind all of them, positioning still plays a silent role.&lt;/p&gt;

&lt;p&gt;The moment something goes wrong,&lt;br&gt;&lt;br&gt;
the moment a layout shifts,&lt;br&gt;&lt;br&gt;
the moment an element overlaps,&lt;br&gt;&lt;br&gt;
the moment a menu disappears,&lt;br&gt;&lt;br&gt;
we all return to the same root question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Where is this element positioned, and relative to what?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Understanding CSS Positioning early saves so much frustration later.&lt;/p&gt;

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

&lt;p&gt;CSS Positioning is not scary.&lt;br&gt;&lt;br&gt;
It is simply misunderstood.&lt;/p&gt;

&lt;p&gt;And once you understand how these five values behave, you will start designing with more confidence, clarity, and creativity.&lt;/p&gt;

&lt;p&gt;Whether you are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a beginner trying to place a small badge
&lt;/li&gt;
&lt;li&gt;a student building a landing page
&lt;/li&gt;
&lt;li&gt;or someone revisiting fundamentals after years
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CSS Positioning is one of those topics that rewards you every time you give it attention.&lt;/p&gt;

&lt;p&gt;If you want the full detailed breakdown, the real examples, and the step‑by‑step mental model, check out my complete WordPress guide:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://blog.shubhra.dev/css-positioning-explained-5-keys/" rel="noopener noreferrer"&gt;CSS Positioning: The 5 Keys to Master Static, Relative, Absolute, Fixed, Sticky&lt;/a&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How CSS Grid Changed the Way I Build Web Layouts</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Fri, 21 Nov 2025 08:36:47 +0000</pubDate>
      <link>https://dev.to/shubhradev/how-css-grid-changed-the-way-i-build-web-layouts-4n74</link>
      <guid>https://dev.to/shubhradev/how-css-grid-changed-the-way-i-build-web-layouts-4n74</guid>
      <description>&lt;p&gt;I remember the first time I tried building a multi-section landing page. Everything seemed fine until I had to align cards, features, and hero sections across different screen sizes. Flexbox was great, it helped me align items neatly along a row or a column. Buttons were easy to center, cards aligned without stress, and navigation bars looked clean. But when it came to arranging rows &lt;em&gt;and&lt;/em&gt; columns simultaneously, I felt like I was juggling invisible boxes.&lt;/p&gt;

&lt;p&gt;At that point, I realized that while Flexbox is incredibly useful, it wasn’t enough for some layouts I wanted to build. That’s when I discovered &lt;strong&gt;CSS Grid&lt;/strong&gt;, and it felt like a whole new world opened up. Suddenly, I could control both rows and columns, manage spacing effortlessly, and create layouts that scaled beautifully on different devices. Unlike Flexbox, which works one direction at a time, Grid lets you think of your layout in two dimensions, like designing a chessboard where each piece has its own space, but the whole board adapts as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CSS Grid Matters
&lt;/h2&gt;

&lt;p&gt;CSS Grid isn’t just a new layout tool. it’s a paradigm shift in how we approach web design. Here are a few reasons why I love using it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Two-Dimensional Control&lt;/strong&gt; – With Grid, you can define both rows and columns simultaneously. This makes complex layouts much simpler than using multiple Flexbox wrappers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simpler Responsiveness&lt;/strong&gt; – Media queries, auto-fit, and minmax make responsive design feel natural. You define the structure once, and it adapts gracefully across devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleaner Code&lt;/strong&gt; – Less nested markup, fewer hacky margins, and more maintainable CSS. Your code feels organized, and it’s easier for others (or future you) to understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible Combinations&lt;/strong&gt; – Grid and Flexbox aren’t competitors. I often use Grid to structure sections and Flexbox inside grid items for precise alignment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of Flexbox as a &lt;strong&gt;Swiss Army knife&lt;/strong&gt;, perfect for one-dimensional tasks. CSS Grid is more like a &lt;strong&gt;blueprint&lt;/strong&gt;: it plans the structure of your entire layout. And when you combine them, building even complex sections becomes surprisingly intuitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Down the Basics
&lt;/h2&gt;

&lt;p&gt;Before diving into full layouts, it’s helpful to understand the building blocks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Grid Container&lt;/strong&gt; – Turn any parent container into a grid by setting &lt;code&gt;display: grid&lt;/code&gt;. Everything inside becomes a grid item automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grid Items&lt;/strong&gt; – Direct children of the container that you can place and size using Grid properties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grid Template Columns&lt;/strong&gt; – Define how many columns your grid will have and their proportions. For example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gap&lt;/strong&gt; – Replace manual margins with gap for both rows and columns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fraction Units (fr)&lt;/strong&gt; – Divide space proportionally. For example, &lt;code&gt;1fr 2fr&lt;/code&gt; gives the first column 1 part and the second column 2 parts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auto-Fit &amp;amp; Auto-Fill&lt;/strong&gt; – Make responsive columns that adjust automatically depending on available space.&lt;/p&gt;

&lt;p&gt;Once you understand these fundamentals, you can start building layouts that scale across devices without headaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  My First Real Project
&lt;/h2&gt;

&lt;p&gt;When I tried my first product grid, I was amazed at how effortless it felt. Previously, I’d spend hours tweaking margins and floats to make cards line up evenly. With CSS Grid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.products&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto-fit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;250px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even with varying content lengths, everything stayed aligned beautifully. Adding hover effects, card spacing, and images became smooth and predictable. I realized I could build dashboards, landing pages, and product sections without overcomplicating the markup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making it Fully Responsive
&lt;/h2&gt;

&lt;p&gt;Responsive design used to be the part I dreaded. CSS Grid made it easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1024px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a few media queries, the layout automatically collapses to fit tablets and mobile screens. No extra wrappers, no messy margin hacks, no complicated nesting. Just clean, intuitive, and flexible layouts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the Basics
&lt;/h2&gt;

&lt;p&gt;Once I mastered the fundamentals, I started experimenting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nested Grids&lt;/strong&gt; – Perfect for dashboards or multi-section layouts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hero Sections&lt;/strong&gt; – Divide the screen visually between text and imagery, all fully responsive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aligning Items&lt;/strong&gt; – Centering, stretching, and fine-tuning placement is straightforward with &lt;code&gt;justify-items&lt;/code&gt; and &lt;code&gt;align-items&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;One of my favorite things is &lt;strong&gt;combining Grid and Flexbox&lt;/strong&gt;. For example, using Flexbox inside a Grid card keeps buttons, icons, and text perfectly aligned without extra CSS gymnastics.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons I Learned While Mastering CSS Grid
&lt;/h2&gt;

&lt;p&gt;When I first started experimenting with CSS Grid, I made some mistakes that slowed me down. These are things I wish I knew from the start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not declaring the grid container properly&lt;/strong&gt; – Sometimes I’d forget &lt;code&gt;display: grid&lt;/code&gt;, and nothing seemed to work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rigid column widths&lt;/strong&gt; – Using fixed pixels made layouts brittle, especially on mobile screens. Switching to flexible fractions (&lt;code&gt;fr&lt;/code&gt;) solved this instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Too many nested grids too soon&lt;/strong&gt; – I tried to nest grids for every tiny section, which made the code messy and hard to debug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skipping mobile testing&lt;/strong&gt; – A layout may look perfect on desktop but break completely on smaller screens if you don’t check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not thinking about combining Flexbox&lt;/strong&gt; – Some elements inside a grid need precise alignment. Using Flexbox inside a grid item is a game-changer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learning from these mistakes helped me write cleaner, more maintainable code and made creating responsive layouts much faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flexbox and CSS Grid: How I Use Them Together
&lt;/h2&gt;

&lt;p&gt;I often get asked: Should I stick to Flexbox or switch entirely to Grid?&lt;/p&gt;

&lt;p&gt;Here’s how I see it now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flexbox&lt;/strong&gt; is perfect when you’re dealing with a single row or column. Think navbars, simple card layouts, or aligning buttons, anywhere you need to align elements along one direction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS Grid&lt;/strong&gt; shines when you need two-dimensional control,rows and columns simultaneously. Dashboards, product sections, or multi-part landing pages are great examples.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trick is not to see them as competitors. I often structure the page using Grid for the main layout and then use Flexbox inside specific grid items to align content perfectly. This combination saves time and keeps layouts consistent across devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Go From Here
&lt;/h2&gt;

&lt;p&gt;If you want a practical, step-by-step guide with real-life examples, screenshots, and fully explained techniques, I’ve written a complete blog post that goes deep into CSS Grid. It covers everything from simple product grids to advanced layouts, nested grids, auto-fit/minmax, and more.&lt;/p&gt;

&lt;p&gt;You can check out the full guide here: &lt;a href="https://blog.shubhra.dev/css-grid-responsive-layouts-guide/" rel="noopener noreferrer"&gt;CSS Grid Responsive Layouts Made Easy: A Complete Guide&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CSS Grid transforms the way you build web layouts, making complex designs intuitive and manageable.&lt;/li&gt;
&lt;li&gt;Combine Grid and Flexbox to get the best of both worlds.&lt;/li&gt;
&lt;li&gt;Start small, experiment with product sections or hero layouts, then gradually explore nested grids and advanced properties.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’ve ever struggled with alignment, responsiveness, or messy layouts, CSS Grid can be a game-changer. And with a little practice, it’ll feel natural, clean, and even enjoyable to work with.&lt;/p&gt;

</description>
      <category>cssgrid</category>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Understanding Flexbox: A Beginner’s Journey to Perfect CSS Alignment</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Mon, 10 Nov 2025 10:53:28 +0000</pubDate>
      <link>https://dev.to/shubhradev/understanding-flexbox-a-beginners-journey-to-perfect-css-alignment-h1a</link>
      <guid>https://dev.to/shubhradev/understanding-flexbox-a-beginners-journey-to-perfect-css-alignment-h1a</guid>
      <description>&lt;p&gt;I still remember the day I met Flexbox.&lt;br&gt;&lt;br&gt;
Not the “oh wow this is cool” kind of meeting, but the “why is nothing aligning right?!” kind. &lt;br&gt;
My divs were misbehaving, my buttons refused to center, and I had started questioning every life choice that led me to CSS.  &lt;/p&gt;

&lt;p&gt;That was the moment I realized:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;understanding Flexbox isn’t about memorizing properties, it’s about changing how you think about layout.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Moment Everything Clicked
&lt;/h2&gt;

&lt;p&gt;I used to picture HTML elements like rigid boxes, stacked on top of each other, bumping into margins, floating aimlessly.&lt;br&gt;&lt;br&gt;
Then one day, while debugging yet another layout mess, someone said:&lt;br&gt;&lt;br&gt;
“Stop fighting the boxes. Let them flex.”&lt;/p&gt;

&lt;p&gt;It sounded poetic… and confusing.&lt;br&gt;&lt;br&gt;
But when I applied &lt;code&gt;display: flex;&lt;/code&gt; for the first time, it was like the page suddenly listened.  &lt;/p&gt;

&lt;p&gt;My boxes started behaving like a team, aligning, wrapping, adjusting naturally without me wrestling with &lt;code&gt;float&lt;/code&gt; or endless &lt;code&gt;position: absolute;&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
That’s when Flexbox stopped feeling like a feature… and started feeling like a mindset.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Flexbox Really Does
&lt;/h2&gt;

&lt;p&gt;Here’s the simplest way I can describe it:&lt;br&gt;&lt;br&gt;
Flexbox lets your elements negotiate space inside a container.  &lt;/p&gt;

&lt;p&gt;They decide based on your rules who gets to stretch, who stays compact, and how they all align together.&lt;/p&gt;

&lt;p&gt;When you declare:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;you’re basically saying:&lt;br&gt;&lt;br&gt;
“Hey container, you’re in charge now. Make your children behave intelligently.”&lt;/p&gt;

&lt;p&gt;From there, a few key properties become your toolkit:&lt;/p&gt;

&lt;p&gt;1) &lt;strong&gt;justify-content&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   It’s all about horizontal alignment.&lt;br&gt;&lt;br&gt;
   Want everything centered across the main axis?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   justify-content: center;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom, your elements snap right into place.&lt;/p&gt;

&lt;p&gt;2) &lt;strong&gt;align-items&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   Now we’re talking vertical balance.&lt;br&gt;&lt;br&gt;
   Need everything to line up perfectly in the middle?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   align-items: center;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s like gravity for your UI.&lt;/p&gt;

&lt;p&gt;3) &lt;strong&gt;flex-direction&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   By default, items align in a row (left to right).&lt;br&gt;&lt;br&gt;
   Change it to a column, and suddenly your layout flows top-to-bottom.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   flex-direction: column;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s like rotating your design without touching HTML.&lt;/p&gt;

&lt;p&gt;4) &lt;strong&gt;flex-wrap&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   Ever had a row that overflowed like an overstuffed suitcase?&lt;br&gt;&lt;br&gt;
   With this, elements gracefully wrap to the next line instead of breaking everything.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;5) &lt;strong&gt;align-content&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
   When you have multiple rows, this property decides how the rows themselves align inside the container.&lt;br&gt;&lt;br&gt;
   It’s subtle but powerful when you’re designing grids or dashboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Developers Fall in Love with Flexbox
&lt;/h2&gt;

&lt;p&gt;Because it feels logical.&lt;br&gt;&lt;br&gt;
You stop micromanaging every pixel and start describing relationships.  &lt;/p&gt;

&lt;p&gt;It’s not about positioning boxes anymore, it’s about teaching your layout how to behave.  &lt;/p&gt;

&lt;p&gt;Once I understood that, my workflow changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No more nested div chaos
&lt;/li&gt;
&lt;li&gt;No more guessing why a button won’t center
&lt;/li&gt;
&lt;li&gt;And best of all, my designs finally stayed responsive without writing 50 media queries
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Use It
&lt;/h2&gt;

&lt;p&gt;Flexbox shines for one-dimensional layouts, anything in a row or column.&lt;br&gt;&lt;br&gt;
If you’re building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;navbars
&lt;/li&gt;
&lt;li&gt;cards in a single line
&lt;/li&gt;
&lt;li&gt;buttons spaced evenly
&lt;/li&gt;
&lt;li&gt;or vertically centered login forms
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flexbox is your best friend.  &lt;/p&gt;

&lt;p&gt;For full grid layouts (like dashboards or galleries), CSS Grid is the next step.&lt;br&gt;&lt;br&gt;
But for most UI tasks, Flexbox is faster, simpler, and more intuitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “Aha!” Lesson
&lt;/h2&gt;

&lt;p&gt;The moment you stop thinking in pixels and start thinking in relationships, CSS becomes fun again.&lt;br&gt;&lt;br&gt;
You realize Flexbox isn’t about commands, it’s about conversation between elements.&lt;br&gt;&lt;br&gt;
And once you feel that click, you’ll never go back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read My Full Flexbox Deep-Dive
&lt;/h2&gt;

&lt;p&gt;This was a gentle walk through the &lt;em&gt;why&lt;/em&gt; behind Flexbox.&lt;br&gt;&lt;br&gt;
If you’d like a more practical, step-by-step guide with examples and clear visual breakdowns, you can read my full post here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://blog.shubhra.dev/fix-css-alignment-issues-flexbox-guide/" rel="noopener noreferrer"&gt;How to Fix Common CSS Alignment Issues : A Simple Flexbox Guide for Beginners&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That one dives into real-world alignment bugs, explains each fix visually, and includes a quick property reference for beginners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;CSS can feel confusing at first, but once you understand the patterns behind it, everything starts to flow.&lt;br&gt;&lt;br&gt;
Flexbox is one of those patterns that makes you fall back in love with frontend again.&lt;/p&gt;

&lt;p&gt;So next time you’re stuck trying to center a div, take a deep breath, set &lt;code&gt;display: flex;&lt;/code&gt;, and let your layout breathe.&lt;/p&gt;

</description>
      <category>css</category>
      <category>flexbox</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Breaking Code, Building Skills: Lessons from My Early JavaScript Errors</title>
      <dc:creator>Shubhra Pokhariya</dc:creator>
      <pubDate>Sun, 02 Nov 2025 10:57:59 +0000</pubDate>
      <link>https://dev.to/shubhradev/breaking-code-building-skills-lessons-from-my-early-javascript-errors-491n</link>
      <guid>https://dev.to/shubhradev/breaking-code-building-skills-lessons-from-my-early-javascript-errors-491n</guid>
      <description>&lt;p&gt;Every coder has that one day when nothing works and the console turns bright red.&lt;br&gt;&lt;br&gt;
That was me too. I remember sitting in front of my laptop, watching endless error messages appear, wondering if maybe coding just wasn’t for me. But slowly, one bug at a time, I began to understand that those “failures” were actually little teachers hiding behind red text.&lt;/p&gt;

&lt;p&gt;Each error shaped how I think, how I stay calm, and how I solve problems. Today, I want to share the first five coding errors that helped me grow into a more confident developer and taught me valuable lessons about patience, logic, and persistence.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. How a Simple Syntax Error Turned Into My Favorite Lesson
&lt;/h2&gt;

&lt;p&gt;My first coding error was the simplest one, and yet it felt like a disaster.&lt;br&gt;&lt;br&gt;
I had written my first JavaScript function and proudly hit “Run,” only to be greeted with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uncaught SyntaxError: Unexpected token&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I stared at my code for ages, convinced something mysterious was wrong, only to realize I had forgotten a closing parenthesis. That tiny bracket had caused the chaos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix was almost funny when I saw it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was my first lesson in humility. Coding errors are not enemies; they’re mirrors showing exactly where you stopped paying attention. Every syntax mistake reminds me to slow down, breathe, and read what the computer is actually telling me.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Mystery of Undefined That Every Coder Faces
&lt;/h2&gt;

&lt;p&gt;Feeling more confident, I started building a tiny to-do app in JavaScript. Everything seemed fine until one line broke my confidence completely:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeError: addTask is not a function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After an hour of confusion, I found the culprit. I had written &lt;code&gt;addtask&lt;/code&gt; in one place and &lt;code&gt;addTask&lt;/code&gt; in another. That one lowercase letter changed everything. JavaScript didn’t care about my intention; it followed the exact name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addtask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Learn JavaScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The corrected version worked instantly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Learn JavaScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That day, I learned that naming consistency is not just good practice, it’s a form of respect for your future self and for anyone reading your code. Many beginners think they have logic issues when in fact, they just have naming errors. Consistency clears more bugs than you’d expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The React Moment That Finally Made “Undefined” Click
&lt;/h2&gt;

&lt;p&gt;When I started learning React, I moved from simple syntax errors to more mysterious ones.&lt;br&gt;&lt;br&gt;
I remember building a &lt;code&gt;UserCard&lt;/code&gt; component that was supposed to display a name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserCard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserCard&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My console flashed with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeError: Cannot read properties of undefined (reading 'name')&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At first, I thought React had a bug. But no, the problem was mine. I hadn’t passed the &lt;code&gt;user&lt;/code&gt; prop at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserCard&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Shubhra&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That fix worked immediately.&lt;br&gt;&lt;br&gt;
It also taught me one of the most important lessons about JavaScript coding errors, &lt;strong&gt;never assume data exists until you’ve confirmed it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, I always handle this safely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserCard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Anonymous User&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That little question mark (&lt;code&gt;?.&lt;/code&gt;) has saved me from countless crashes since.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The Next.js Fetch Coding Error That Tested My Patience
&lt;/h2&gt;

&lt;p&gt;My next big challenge came in a Next.js project where I needed to fetch data from an API. The setup looked perfect, but the console threw a scary red message:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error: fetch failed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I checked my connection, rechecked my endpoint, and even switched networks. Nothing worked. Finally, after far too long, I saw the real issue, I had typed &lt;code&gt;htp://&lt;/code&gt; instead of &lt;code&gt;https://&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;htp://api.example.com/data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looked right at a glance, but one missing “s” broke everything.&lt;br&gt;&lt;br&gt;
Once corrected, it ran beautifully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.example.com/data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That bug taught me patience and the power of slowing down.&lt;br&gt;&lt;br&gt;
When you face coding errors like this, it’s not always about fixing, sometimes it’s about observing. Debugging isn’t rushing to solve; it’s tracing your logic calmly, one small step at a time.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. When a Logic Mistake Made Everything Click
&lt;/h2&gt;

&lt;p&gt;My final lesson came from a bug that didn’t crash my code, it just gave me the wrong answer.&lt;br&gt;&lt;br&gt;
I wrote a small loop to total expenses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result was &lt;strong&gt;NaN&lt;/strong&gt;, and I couldn’t figure out why.&lt;br&gt;&lt;br&gt;
Then I noticed the condition: I had used &lt;code&gt;&amp;lt;=&lt;/code&gt; instead of &lt;code&gt;&amp;lt;&lt;/code&gt;. That tiny sign caused the loop to access &lt;code&gt;prices[3]&lt;/code&gt;, which didn’t exist.&lt;/p&gt;

&lt;p&gt;Corrected version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one small fix changed everything. Logic errors like this are the best teachers. They don’t shout in red text, they whisper. They make you think more deeply and check your assumptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What These Coding Errors Taught Me
&lt;/h2&gt;

&lt;p&gt;Looking back, each of these moments shaped me as a developer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Syntax errors taught me precision.&lt;/li&gt;
&lt;li&gt;Undefined function errors taught me discipline.&lt;/li&gt;
&lt;li&gt;React property errors taught me data awareness.&lt;/li&gt;
&lt;li&gt;Fetch errors taught me patience.&lt;/li&gt;
&lt;li&gt;Logic errors taught me analytical thinking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, they gave me a mindset: that debugging isn’t punishment, it’s exploration.&lt;br&gt;&lt;br&gt;
Each fix gave me confidence, and each small victory reminded me why I love building things from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging and Growth Go Hand in Hand
&lt;/h2&gt;

&lt;p&gt;When I began, I thought great developers wrote perfect code. Now I know they write buggy code, but they fix it thoughtfully. Debugging is where confidence, creativity, and calm meet.&lt;/p&gt;

&lt;p&gt;Those first five coding errors built the foundation of my developer journey. They taught me to think clearly, to listen to my console without fear, and to enjoy the learning process.&lt;/p&gt;

&lt;p&gt;If you are facing your own set of errors, don’t fight them.&lt;br&gt;&lt;br&gt;
Ask your code what it’s trying to teach you.&lt;br&gt;&lt;br&gt;
That’s how confusion turns into confidence and every mistake becomes a milestone.&lt;br&gt;
👉 Read the full story here: &lt;a href="https://blog.shubhra.dev/my-first-5-coding-errors/" rel="noopener noreferrer"&gt;My First 5 Coding Errors&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>codingerror</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
