Initializing Enclave...

How to Fix 'Found Page Without a React Component as Default Export' in Next.js

Threat/Impact Level: HIGH | Downtime Risk: HIGH | Time to Fix: 2–10 mins


TL;DR

  • What broke: A file inside pages/ is missing a valid React component as its default export — Next.js cannot map it to a route, so next build hard-fails.
  • How to fix it: Ensure every file in pages/ (except _app.tsx, _document.tsx, and API routes under pages/api/) exports a React functional or class component as default.
  • Fast path: Use our Client-Side Sandbox above to paste your offending page file and auto-refactor it — it detects the missing/invalid export and rewrites it instantly.

The Incident (What Does the Error Mean?)

During next build, the framework statically analyzes every file in your pages/ directory. It expects each file's default export to be a renderable React component. When it finds anything else — or nothing — it throws:

Build optimization failed: found page without a React Component as default export in pages directory
  pages/dashboard.tsx

Immediate consequence: The build exits with a non-zero code. Your CI/CD pipeline fails. Nothing ships. If this slips through a misconfigured pipeline that deploys on partial success, you get a broken route that 500s in production.

Common triggers:

Scenario Example
File exports a plain object export default { title: 'page' }
File exports a string or primitive export default 'hello'
File has only named exports, no default export const Page = () => <div/>
File is a utility/helper accidentally placed in pages/ A constants file, a type-only file
Async function not wrapped as a component export default async function getData()
Empty file committed by accident

The Blast Radius

This is not a runtime warning — it is a compile-time hard block. The blast radius depends on your pipeline:

  • Monorepo with shared pages/ symlinks: One bad file blocks builds for every app consuming that directory.
  • Incremental Static Regeneration (ISR) at scale: If this surfaces during a revalidation build triggered by on-demand ISR, your entire revalidation queue stalls.
  • Preview deployments (Vercel/Netlify): Every PR gets a failed deploy, breaking the review workflow for the whole team.
  • No pre-commit hooks: Developers only discover this on push, wasting CI minutes and blocking the merge queue.

There is no graceful degradation here. Next.js will not skip the bad file and build the rest. It stops.


How to Fix It

Basic Fix

The offending file must export a React component as default. Minimum viable fix:

- export default { title: 'Dashboard' }
+ import React from 'react'
+
+ export default function DashboardPage() {
+   return <main><h1>Dashboard</h1></main>
+ }
- export const ProfilePage = () => <div>Profile</div>
+ const ProfilePage = () => <div>Profile</div>
+
+ export default ProfilePage
- export default async function fetchData() {
-   return await fetch('/api/data')
- }
+ // Move data-fetching logic to getServerSideProps or a lib/ utility
+ export default function DataPage() {
+   return <div>Data</div>
+ }
+
+ export async function getServerSideProps() {
+   const res = await fetch('/api/data')
+   const data = await res.json()
+   return { props: { data } }
+ }

Enterprise Best Practice

Rule 1: Nothing non-component lives in pages/. Move all utilities, constants, types, and helpers to lib/, utils/, or src/ directories. Enforce this with path aliasing in tsconfig.json.

Rule 2: Use a TypeScript page type contract. Force every page file to satisfy the NextPage type, which will surface missing default exports at compile time before next build even runs:

- const Dashboard = () => <div>Dashboard</div>
- export { Dashboard }
+ import type { NextPage } from 'next'
+
+ const Dashboard: NextPage = () => <div>Dashboard</div>
+
+ export default Dashboard

Rule 3: ESLint enforcement. The @next/next ESLint plugin includes rules that catch this before commit:

- // .eslintrc.json
- { "extends": ["next"] }
+ // .eslintrc.json
+ {
+   "extends": ["next/core-web-vitals"],
+   "rules": {
+     "@next/next/no-page-custom-font": "error"
+   }
+ }

Run next lint as a pre-build step — it will flag invalid page exports before next build wastes your CI minutes.


💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

1. Pre-commit: lint-staged + next lint

# .husky/pre-commit
npx lint-staged

# lint-staged.config.js
module.exports = {
  'pages/**/*.{ts,tsx,js,jsx}': ['next lint --fix', 'git add'],
}

2. CI pipeline gate — fail fast before next build

# .github/workflows/ci.yml
jobs:
  lint-and-build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - name: Lint (catches invalid page exports)
        run: npx next lint
      - name: Build
        run: npx next build

By running next lint as a separate, earlier step, you get a fast failure with a precise file reference instead of the cryptic build optimizer error.

3. Custom ESLint rule for default export enforcement

If you want zero tolerance across all pages:

// eslint-plugin-local/rules/require-page-default-export.js
module.exports = {
  create(context) {
    const filename = context.getFilename()
    if (!filename.includes('/pages/')) return {}
    if (filename.includes('/api/')) return {}
    let hasDefaultExport = false
    return {
      ExportDefaultDeclaration() { hasDefaultExport = true },
      'Program:exit'() {
        if (!hasDefaultExport) {
          context.report({ loc: { line: 1, column: 0 }, message: 'Page files must have a default React component export.' })
        }
      },
    }
  },
}

4. Checkov / Semgrep for IaC-adjacent Next.js config checks

If you manage Next.js deployments via Terraform or CDK, add a Semgrep rule to your pipeline that scans the pages/ directory for files lacking default exports during the plan/preview stage — catching it before infrastructure provisioning even starts.


Bottom line: This error is 100% preventable with next lint in CI. Every minute your build sits broken on this is a minute you didn't have a lint gate.

Related Diagnostics

"Part of the Syntax Utility Matrix."

View all 153 Syntax Tools →