{"id":1555,"date":"2026-08-19T11:46:54","date_gmt":"2026-08-19T11:46:54","guid":{"rendered":"https:\/\/www.projectimmerse.com\/blog\/?p=1555"},"modified":"2026-08-19T12:18:12","modified_gmt":"2026-08-19T12:18:12","slug":"next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas","status":"publish","type":"post","link":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/","title":{"rendered":"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-1024x1024.png\" alt=\"Retro developer workspace illustrating Next.js framework gotchas with middleware, prerendering, Postgres, and TypeScript\" class=\"wp-image-1562\" srcset=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-1024x1024.png 1024w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-300x300.png 300w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-150x150.png 150w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-768x768.png 768w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-100x100.png 100w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas.png 1254w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/a><figcaption class=\"wp-element-caption\">Next.js can feel confusing when framework conventions, prerendering behavior, database quirks, and TypeScript rules aren&#8217;t obvious at first.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If you&#8217;ve ever built something with Next.js and Postgres, you&#8217;ve probably hit a moment where the app does something that looks broken but technically isn&#8217;t. Your database ID jumps from 2 to 35 out of nowhere. Next.js throws a scary-looking error about &#8220;blocking&#8221; your route. Your editor yells at you for naming a file wrong. None of these mean you broke something \u2014 they mean the framework is trying to tell you how it actually works under the hood.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here are three of the most common &#8220;wait, is this a bug?&#8221; moments, explained without the panic.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Why Your Middleware Isn&#8217;t Running (Even Though the Code Is &#8220;Right&#8221;)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s a fun one: you write a perfectly valid function that redirects requests, the logic is airtight, TypeScript isn&#8217;t complaining \u2014 and Next.js just&#8230; never runs it. No error. No warning. It just quietly does nothing.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nexport function proxy(request: NextRequest) {\n  if (request.nextUrl.pathname.startsWith(&quot;\/admin&quot;)) {\n    return NextResponse.redirect(new URL(&quot;\/&quot;, request.url));\n  }\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">This looks like middleware. It smells like middleware. But Next.js won&#8217;t touch it, for two very specific, very unforgiving reasons: the file isn&#8217;t named&nbsp;<code>middleware.ts<\/code>, and the function isn&#8217;t named&nbsp;<code>middleware<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next.js doesn&#8217;t scan your project for &#8220;a function that looks like it redirects things.&#8221; It looks for one exact convention: a file called&nbsp;<code>middleware.ts<\/code>&nbsp;(or&nbsp;<code>.js<\/code>) at your project root, or inside&nbsp;<code>src\/<\/code>, exporting a function named&nbsp;<code>middleware<\/code>. Call it&nbsp;<code>proxy<\/code>, put it in the wrong folder, or misspell it, and you don&#8217;t get an error \u2014 you just get silence, which is arguably worse.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The fix is boring on purpose:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n\/\/ middleware.ts (project root or src\/)\nimport { NextRequest, NextResponse } from &quot;next\/server&quot;;\n\nexport function middleware(request: NextRequest) {\n  if (request.nextUrl.pathname.startsWith(&quot;\/admin&quot;)) {\n    return NextResponse.redirect(new URL(&quot;\/&quot;, request.url));\n  }\n}\n\nexport const config = {\n  matcher: &quot;\/((?!api|_next\/static|_next\/image|.*\\\\.png$).*)&quot;,\n};\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">That&nbsp;<code>config.matcher<\/code>&nbsp;is worth a second look too \u2014 it&#8217;s a regex telling Next.js which routes should even bother running your middleware. The pattern above says &#8220;run on everything except API routes, static assets, optimized images, and PNGs,&#8221; which keeps you from redirecting your own favicon by accident.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The lesson: some frameworks infer intent from your code. Next.js middleware isn&#8217;t one of them \u2014 it wants the exact filename and the exact export name, full stop.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">&#8220;Blocking RouteServer&#8221; \u2014 Why Next.js Is Yelling About Prerendering<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-framework-gotchas-middleware-prerendering-1024x1024.png\" alt=\"Next.js middleware, prerendering, Postgres ID gaps, and TypeScript .ts versus .tsx gotchas\" class=\"wp-image-1565\" srcset=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-framework-gotchas-middleware-prerendering-1024x1024.png 1024w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-framework-gotchas-middleware-prerendering-300x300.png 300w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-framework-gotchas-middleware-prerendering-150x150.png 150w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-framework-gotchas-middleware-prerendering-768x768.png 768w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-framework-gotchas-middleware-prerendering-100x100.png 100w, https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-framework-gotchas-middleware-prerendering.png 1254w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">Next.js framework gotchas make more sense once you understand the conventions behind middleware, prerendering, database IDs, and TypeScript file extensions.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If you&#8217;ve fetched data straight from a database inside a page component, you may have run into this warning:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Next.js encountered uncached data during prerendering. This prevents the route from being prerendered, blocking navigation and leading to a slower user experience.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Translated: Next.js tried to build this page ahead of time (prerendering), but your database call can only happen when a real request comes in. That makes the whole page &#8220;block&#8221; \u2014 nobody sees anything until the query finishes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next.js gives you three honest options here, not just one &#8220;correct&#8221; answer:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1. Stream it with Suspense.<\/strong>&nbsp;Pull the dynamic part into its own component, wrap it in Suspense, and let the rest of the page load instantly while that piece streams in behind a fallback.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nasync function PostsList() {\n  const posts = await prisma.post.findMany();\n  return &lt;ul&gt;{\/* render posts *\/}&lt;\/ul&gt;;\n}\n\nexport default function PostsPage() {\n  return (\n    &lt;div&gt;\n      &lt;h1&gt;Posts&lt;\/h1&gt;\n      &lt;Suspense fallback={&lt;p&gt;Loading...&lt;\/p&gt;}&gt;\n        &lt;PostsList \/&gt;\n      &lt;\/Suspense&gt;\n    &lt;\/div&gt;\n  );\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><strong>2. Cache it.<\/strong>&nbsp;If the data doesn&#8217;t need to be fetched fresh on every request, mark the function with &#8220;use cache&#8221; so Next.js can treat it like static content.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3. Just allow the block.<\/strong>&nbsp;Sometimes a page genuinely needs fresh data every time and there&#8217;s no useful &#8220;shell&#8221; to show early. In that case you can tell Next.js you&#8217;re doing this on purpose:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: xml; title: ; notranslate\" title=\"\">\nexport const instant = false;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Worth knowing:&nbsp;<code>instant = false<\/code>&nbsp;doesn&#8217;t change how your page behaves at all. It doesn&#8217;t optimize anything or add caching. It just turns off the warning for that one route, essentially saying &#8220;yes, I know, I meant to do that.&#8221; It&#8217;s an escape hatch, not a fix \u2014 treat it as a temporary pass, not a permanent answer, unless you&#8217;re sure that route genuinely needs fresh data on every load.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">.ts vs .tsx: The Extension That Actually Means Something<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This one trips up a lot of people moving into TypeScript + React, and the rule is simpler than it looks:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Does the file contain JSX (like &lt;div&gt; or &lt;Button \/&gt;)? Use .tsx. Does it not? Use .ts.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s genuinely it. The extension isn&#8217;t about what a file &#8220;does&#8221; conceptually \u2014 it&#8217;s a signal to the compiler about how to parse&nbsp;<code>&lt;<\/code>&nbsp;characters. Without&nbsp;<code>.tsx<\/code>, TypeScript can&#8217;t tell whether&nbsp;<code>&lt;Post&gt;<\/code>&nbsp;is a JSX tag or a generic type comparison, and it&#8217;ll throw a fit.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A quick cheat sheet:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Page or component that returns markup \u2192 .tsx<\/li>\n\n\n\n<li>Server action that just runs logic and talks to a database \u2192 .ts<\/li>\n\n\n\n<li>Utility functions, type definitions, middleware \u2192 .ts<\/li>\n\n\n\n<li>Anything with a literal\u00a0<code>return (&lt;div>...)<\/code>\u00a0in it \u2192 .tsx<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<code>.ts<\/code>&nbsp;file can absolutely still be used by React components, call hooks indirectly, or be deeply &#8220;React-related&#8221; \u2014 the extension only cares about whether JSX syntax physically appears in that specific file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Takeaway<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">None of these are bugs. They&#8217;re the framework and the database being honest about tradeoffs you didn&#8217;t know you were making:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Postgres trades gap-free IDs for speed \u2014 deal with it, don&#8217;t fight it.<\/li>\n\n\n\n<li>Next.js wants you to be explicit about what&#8217;s fast and what&#8217;s allowed to be slow.<\/li>\n\n\n\n<li>TypeScript just wants to know, up front, whether it should expect angle brackets to mean HTML or math.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Once you know the &#8220;why,&#8221; none of these errors are scary anymore \u2014 they&#8217;re just the tools doing their job a little too honestly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;ve ever built something with Next.js and Postgres, you&#8217;ve probably hit a moment where the app does something that looks broken but technically isn&#8217;t. Your database ID jumps from 2 to 35 out of nowhere. Next.js throws a scary-looking error about &#8220;blocking&#8221; your route. Your editor yells at you for naming a file wrong. &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[56],"tags":[],"class_list":["post-1555","post","type-post","status-publish","format-standard","hentry","category-programming-fundamentals"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas - Project Immerse<\/title>\n<meta name=\"description\" content=\"Next.js middleware silently not running? Blocking prerender errors? Confused about .ts vs .tsx? Here&#039;s what&#039;s actually happening \u2014 and how to fix it.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas - Project Immerse\" \/>\n<meta property=\"og:description\" content=\"Next.js middleware silently not running? Blocking prerender errors? Confused about .ts vs .tsx? Here&#039;s what&#039;s actually happening \u2014 and how to fix it.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/\" \/>\n<meta property=\"og:site_name\" content=\"Project Immerse\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-19T11:46:54+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-08-19T12:18:12+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-1024x1024.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Alex Mercer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Alex Mercer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/\"},\"author\":{\"name\":\"Alex Mercer\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#\\\/schema\\\/person\\\/c53f2864be524ee6fa08a7e4800dd1e5\"},\"headline\":\"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas\",\"datePublished\":\"2026-08-19T11:46:54+00:00\",\"dateModified\":\"2026-08-19T12:18:12+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/\"},\"wordCount\":934,\"image\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/nextjs-confused-me-on-purpose-framework-gotchas-1024x1024.png\",\"articleSection\":[\"Programming Fundamentals\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/\",\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/\",\"name\":\"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas - Project Immerse\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/nextjs-confused-me-on-purpose-framework-gotchas-1024x1024.png\",\"datePublished\":\"2026-08-19T11:46:54+00:00\",\"dateModified\":\"2026-08-19T12:18:12+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#\\\/schema\\\/person\\\/c53f2864be524ee6fa08a7e4800dd1e5\"},\"description\":\"Next.js middleware silently not running? Blocking prerender errors? Confused about .ts vs .tsx? Here's what's actually happening \u2014 and how to fix it.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/nextjs-confused-me-on-purpose-framework-gotchas.png\",\"contentUrl\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/nextjs-confused-me-on-purpose-framework-gotchas.png\",\"width\":1254,\"height\":1254},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/\",\"name\":\"Project Immerse\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/#\\\/schema\\\/person\\\/c53f2864be524ee6fa08a7e4800dd1e5\",\"name\":\"Alex Mercer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/alex-mercer-author-150x150.png\",\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/alex-mercer-author-150x150.png\",\"contentUrl\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/alex-mercer-author-150x150.png\",\"caption\":\"Alex Mercer\"},\"description\":\"Alex Mercer is a writer and contributor at Project Immerse, covering web design, WordPress, web development, SEO, digital strategy, emerging technology, and the evolving world of the web. His work focuses on practical ideas, useful tools, and approachable guidance that help creators, developers, and business owners build better digital experiences. Alex writes with a hands-on, curiosity-driven approach, exploring both established web practices and new technologies shaping how websites are designed, built, and discovered.\",\"sameAs\":[\"https:\\\/\\\/www.projectimmerse.com\"],\"url\":\"https:\\\/\\\/www.projectimmerse.com\\\/blog\\\/author\\\/projectimmerse\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas - Project Immerse","description":"Next.js middleware silently not running? Blocking prerender errors? Confused about .ts vs .tsx? Here's what's actually happening \u2014 and how to fix it.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/","og_locale":"en_US","og_type":"article","og_title":"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas - Project Immerse","og_description":"Next.js middleware silently not running? Blocking prerender errors? Confused about .ts vs .tsx? Here's what's actually happening \u2014 and how to fix it.","og_url":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/","og_site_name":"Project Immerse","article_published_time":"2026-08-19T11:46:54+00:00","article_modified_time":"2026-08-19T12:18:12+00:00","og_image":[{"width":1024,"height":1024,"url":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-1024x1024.png","type":"image\/png"}],"author":"Alex Mercer","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Alex Mercer","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/#article","isPartOf":{"@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/"},"author":{"name":"Alex Mercer","@id":"https:\/\/www.projectimmerse.com\/blog\/#\/schema\/person\/c53f2864be524ee6fa08a7e4800dd1e5"},"headline":"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas","datePublished":"2026-08-19T11:46:54+00:00","dateModified":"2026-08-19T12:18:12+00:00","mainEntityOfPage":{"@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/"},"wordCount":934,"image":{"@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/#primaryimage"},"thumbnailUrl":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-1024x1024.png","articleSection":["Programming Fundamentals"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/","url":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/","name":"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas - Project Immerse","isPartOf":{"@id":"https:\/\/www.projectimmerse.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/#primaryimage"},"image":{"@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/#primaryimage"},"thumbnailUrl":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas-1024x1024.png","datePublished":"2026-08-19T11:46:54+00:00","dateModified":"2026-08-19T12:18:12+00:00","author":{"@id":"https:\/\/www.projectimmerse.com\/blog\/#\/schema\/person\/c53f2864be524ee6fa08a7e4800dd1e5"},"description":"Next.js middleware silently not running? Blocking prerender errors? Confused about .ts vs .tsx? Here's what's actually happening \u2014 and how to fix it.","breadcrumb":{"@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/#primaryimage","url":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas.png","contentUrl":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/08\/nextjs-confused-me-on-purpose-framework-gotchas.png","width":1254,"height":1254},{"@type":"BreadcrumbList","@id":"https:\/\/www.projectimmerse.com\/blog\/next-js-confused-me-on-purpose-a-field-guide-to-framework-gotchas\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.projectimmerse.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Next.js Confused Me on Purpose: A Field Guide to Framework Gotchas"}]},{"@type":"WebSite","@id":"https:\/\/www.projectimmerse.com\/blog\/#website","url":"https:\/\/www.projectimmerse.com\/blog\/","name":"Project Immerse","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.projectimmerse.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.projectimmerse.com\/blog\/#\/schema\/person\/c53f2864be524ee6fa08a7e4800dd1e5","name":"Alex Mercer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/09\/alex-mercer-author-150x150.png","url":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/09\/alex-mercer-author-150x150.png","contentUrl":"https:\/\/www.projectimmerse.com\/blog\/wp-content\/uploads\/2026\/09\/alex-mercer-author-150x150.png","caption":"Alex Mercer"},"description":"Alex Mercer is a writer and contributor at Project Immerse, covering web design, WordPress, web development, SEO, digital strategy, emerging technology, and the evolving world of the web. His work focuses on practical ideas, useful tools, and approachable guidance that help creators, developers, and business owners build better digital experiences. Alex writes with a hands-on, curiosity-driven approach, exploring both established web practices and new technologies shaping how websites are designed, built, and discovered.","sameAs":["https:\/\/www.projectimmerse.com"],"url":"https:\/\/www.projectimmerse.com\/blog\/author\/projectimmerse\/"}]}},"_links":{"self":[{"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/posts\/1555","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/comments?post=1555"}],"version-history":[{"count":4,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/posts\/1555\/revisions"}],"predecessor-version":[{"id":1566,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/posts\/1555\/revisions\/1566"}],"wp:attachment":[{"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/media?parent=1555"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/categories?post=1555"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.projectimmerse.com\/blog\/wp-json\/wp\/v2\/tags?post=1555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}