
Content creator and developer at UICraft Marketplace, sharing insights and tutorials on modern web development.
Save hours of development time with our premium Next.js templates. Built with Next.js 16, React 19, and Tailwind CSS 4.
Get the latest articles, tutorials, and product updates delivered to your inbox.
High-traffic Next.js applications often suffer from poor CDN cache hit rates due to how React Server Component payloads are hashed during client-side navigation. This guide uses real performance benchmarks to demonstrate fixes that dramatically improve edge caching efficiency.

Next.js Cache Components introduce a powerful static shell optimization, but they conflict with draftMode preview workflows. Learn how to conditionally bypass caching when editors need to preview unpublished content from your headless CMS.

Running `next lint` with ESLint 9 throws cryptic "Unknown options" errors for useEslintrc and extensions. This guide explains why ESLint 9's flat config breaks Next.js linting and provides clear solutions to get your project working again.
You're deploying to Vercel, feeling confident about your latest changes. Then the build fails with this cryptic error:
Error occurred prerendering page "/_not-found"
TypeError: Cannot read properties of null (reading 'auth')
If you're hitting this Next.js prerender error _not-found auth issue, you're not alone. This error has tripped up many developers, especially those using authentication wrappers in their root layouts. Let's break down what's happening and how to fix it properly.
The error typically surfaces during next build when Next.js attempts to statically prerender the /_not-found page. The full error often looks something like this:
Generating static pages (0/8) [= ]
Error occurred prerendering page "/_not-found".
Read more: https://nextjs.org/docs/messages/prerender-error
TypeError: Cannot read properties of null (reading 'auth')
at RootLayout (/app/layout.tsx:25:32)
...
> Export encountered errors on following paths:
/_not-found/page: /_not-found
This issue gained significant attention in GitHub issue #65447, where developers reported similar failures after upgrading to Next.js 14.2.x, particularly when using the pageExtensions configuration option. However, the root cause isn't limited to pageExtensions—it's fundamentally about accessing authentication context during static prerendering.
The frustrating part? Your app works perfectly during . It only blows up when you try to build for production.
next devTo understand this error, you need to grasp how Next.js handles the _not-found page differently from your other routes.
During next build, Next.js prerenders certain pages as static HTML to optimize performance. The _not-found page is one of these. It gets generated at build time—without any request context, session data, or authentication information.
Here's the critical insight: there is no user session during build time. No cookies, no headers, no authenticated user. It's just Next.js generating static HTML on your CI server.
Many applications wrap their root layout with an authentication provider or access session data directly. A common pattern looks like this:
// ❌ BROKEN: Accessing auth in layout without null checks
// app/layout.tsx
import { auth } from "@/lib/auth";
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const session = await auth();
// This line throws during _not-found prerendering
// because session is null at build time
const userName = session.user.name;
return (
<html>
<body>
<nav>
When Next.js prerenders /_not-found, it renders your root layout.tsx as part of the page tree. If that layout calls auth() and immediately tries to access properties on the result without checking for null, you get the dreaded TypeError.
The GitHub issue #65447 specifically mentions pageExtensions because this configuration can affect how Next.js discovers and processes special files like not-found.tsx. When you use custom page extensions (e.g., ['page.tsx', 'page.ts']), Next.js might not properly resolve your custom not-found.page.tsx file, falling back to an internal _not-found route that still renders through your root layout.
The combination of:
pageExtensions configuration_not-found page being statically prerenderedCreates the perfect storm for this Next.js prerender error _not-found auth failure.
The fix is straightforward once you understand the problem: never assume authentication data exists in components that render during static builds.
The simplest fix is using optional chaining (?.) to safely access potentially null properties:
// ✅ FIXED: Using optional chaining for null safety
// app/layout.tsx
import { auth } from "@/lib/auth";
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const session = await auth();
// Safe access with optional chaining
const userName = session?.user?.name;
return (
<html>
<body>
<nav>
{userName ? (
For more complex auth-dependent UI, use an early return pattern:
// ✅ FIXED: Guard clause for auth-dependent logic
// app/layout.tsx
import { auth } from "@/lib/auth";
import { AuthProvider } from "@/components/auth-provider";
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const session = await auth();
// Guard clause - if no session, render minimal layout
if (!session) {
return (
<html>
<body>
<nav>
If your authentication UI is complex, consider moving it to a client component that handles its own loading state:
// ✅ FIXED: Server layout with client-side auth component
// app/layout.tsx
import { AuthHeader } from "@/components/auth-header";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
<AuthHeader />
{children}
</body>
</html>
);
}// components/auth-header.tsx
"use client";
import { useSession } from "next-auth/react";
export function AuthHeader() {
const { data: session, status } = useSession();
if (status === "loading") {
return (
<nav>
<span>Loading...</span>
</nav>
);
}
return (
<nav>
{session?.user ? (
This approach moves the auth logic entirely to the client, avoiding the prerender issue altogether. The trade-off is a slight flash of loading state on initial page load.
If you're using pageExtensions and encountering this issue, ensure your special files follow the naming convention:
// next.config.js
module.exports = {
pageExtensions: ["page.tsx", "page.ts"],
};With this config, your not-found file should be named not-found.page.tsx:
app/
├── layout.page.tsx
├── page.page.tsx
├── not-found.page.tsx // Must match pageExtensions
└── error.page.tsx
Important: Even with correct file naming, you still need the null-safety patterns above. The file naming just ensures Next.js finds your custom 404 page.
The best defense against prerender errors is catching them before they hit your CI pipeline. Here's a prevention checklist:
Make it a habit to run next build locally before pushing:
# Run a production build locally
npm run build
# Or with yarn
yarn buildThis will surface any prerender errors immediately, saving you the round-trip to Vercel.
Automate the check with a git hook using Husky:
# .husky/pre-push
npm run buildFor team projects, add an explicit build step in your CI:
# .github/workflows/ci.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm ci
- run: npm run build # Catches prerender errorsReview your root layout.tsx for any assumptions about request-time data:
Consider creating a reusable wrapper that handles null cases:
// lib/safe-auth.ts
import { auth } from "@/lib/auth";
export async function safeAuth() {
try {
const session = await auth();
return session;
} catch (error) {
// During static generation, auth might throw
console.warn("Auth unavailable during static generation");
return null;
}
}
export function getAuthUser(session: Awaited<ReturnType<typeof auth>>) {
return {
name:
Using this in your layout:
// app/layout.tsx
import { safeAuth, getAuthUser } from "@/lib/safe-auth";
export default async function RootLayout({ children }) {
const session = await safeAuth();
const user = getAuthUser(session);
return (
<html>
<body>
<nav>
<span>Welcome, {user.name}</span>
</nav>
{children}
This pattern centralizes your null-safety logic and makes it reusable across your application.
The _not-found page is statically prerendered during next build, meaning there's no session, cookies, or request context available.
Auth wrappers in root layouts must handle null cases using optional chaining (?.), guard clauses, or by isolating auth logic in client components.
The pageExtensions config can complicate things by affecting how Next.js discovers special files like not-found.tsx. Ensure your files match the configured extensions.
Always run next build locally before deploying to catch Next.js prerender error _not-found auth issues early, rather than debugging them in your CI logs.
Create defensive auth utilities that gracefully handle undefined sessions, making your codebase resilient to static generation edge cases.
Audit your root layout right now. Search for any direct property access on session or auth objects without null checks.
Run next build locally to verify your fixes work before pushing to your CI.
Set up pre-push hooks or CI checks to catch prerender errors automatically.
Review the GitHub issue #65447 for community workarounds if you're dealing with the pageExtensions variant of this problem.
Consider the client component approach if your auth UI is complex—it trades a loading flash for complete immunity from prerender issues.
The Next.js prerender error _not-found auth issue is ultimately about understanding the boundary between static and dynamic rendering. Once you internalize that build-time rendering has no request context, defensive coding becomes second nature. Your future self—and your CI pipeline—will thank you.