Next.js

Fix 'authOptions' is not a valid Route export field

Reproduced on Next.js 13.4.3 (Linux and Windows), 15.4.11 and 15.5.27: why exporting authOptions from the NextAuth route breaks the build only, and the one-file move that fixes it.

Mahdi Ben RhoumaMahdi Ben Rhouma
8 min read

The asker's App Router project with NextAuth.js ran fine under next dev, but next build stopped at "Linting and checking validity of types" with a type error that points at a file you never wrote, inside .next/types/. The cause is one word in app/api/auth/[...nextauth]/route.ts: the export in front of authOptions.

TL;DR#

  • Cause: a Route Handler file may only export HTTP method handlers (GET, POST, …) and route segment config. export const authOptions is neither, and the build's type check rejects it on every version tested from 13.4.3 to 15.5.27 (16.x accepted it in the same test).
  • Fix: move the options object to an ordinary module such as lib/auth.ts, export it from there, and import it in route.ts. Keep exporting only GET and POST from the route.
  • Shortcut that also builds: drop the export keyword and keep the object in route.ts, if nothing else in the app needs it.
  • Reproduced on Next.js 13.4.3 with next-auth 4.22.1, on Linux and on Windows. Moving the options fixed both; dropping export was tested on Linux.

The error, in its two forms#

The Stack Overflow question shows the raw TypeScript form, with the generated checker file in the header:

text
.next/types/app/api/auth/[...nextauth]/route.ts:8:13
Type error: Type 'OmitWithTag<typeof import("D:/4 - Coding/Training/NextAuth/next-auth-new/app/api/auth/[...nextauth]/route"), "config" | "generateStaticParams" | "revalidate" | "dynamic" | "dynamicParams" | ... 9 more ... | "PATCH", "">' does not satisfy the constraint '{ [x: string]: never; }'.
  Property 'authOptions' is incompatible with index signature.
    Type 'AuthOptions' is not assignable to type 'never'.

The same route.ts, built on Linux in Docker (node:18, Next.js 13.4.3), prints a shorter message that names the offending export directly:

text
app/api/auth/[...nextauth]/route.ts
Type error: Route "app/api/auth/[...nextauth]/route.ts" does not match the required types of a Next.js Route.
  "authOptions" is not a valid Route export field.

Built natively on Windows 11 (Next.js 13.4.3, next-auth 4.22.1, TypeScript 5.0.4, Node 26.7.0), it printed the raw form again, .next/types/app/api/auth/[...nextauth]/route.ts:8:13 header and code frame included, with the checkFields<Diff<{ line underlined. Same file, same Next.js version, two messages. Both mean the same thing, and the second one is the easier to search for: it is also the title of vercel/next.js issue 56832, while issue 50870 reports the raw form from a Windows path.

Why it happens#

The route.js reference defines what a Route Handler file is for. Its HTTP Methods section reads: "The following HTTP methods are supported: GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS." Its Segment Config Options section adds that "Route Handlers use the same route segment configuration as pages and layouts" (dynamic, revalidate, runtime and the rest). Nothing else belongs in the file's exports.

During next build, Next.js 13.4.3 to 15.5.27 generate a checker file per route under .next/types/app/… (the 15.5.27 build also writes a validator.ts next to them). That file takes the type of your module, removes every name it allows (the union in the error message: the HTTP methods plus config, generateStaticParams, revalidate, dynamic, dynamicParams and so on), and requires what is left to be an object whose every property is never. Any leftover export is a property that cannot be never, so TypeScript reports Property 'authOptions' is incompatible with index signature. That is the checkFields<Diff<{ … }>> line the code frame points at.

The TypeScript configuration page states the consequence: "Next.js fails your production build (next build) when TypeScript errors are present in your project." The asker reports the app working in development, which is consistent with that: the check is a build step.

Why so many NextAuth projects export authOptions#

The habit comes from the Pages Router. The NextAuth.js v4 Next.js page tells you to export the options from [...nextauth].ts so that getServerSession can reuse them, and its App Router example still imports them with import { authOptions } from "pages/api/auth/[...nextauth]". That is the documented pattern for pages/api. Copy the same export const authOptions into an App Router route.ts and the build fails.

The same page already contains the App Router-safe shape. Its tip creates an auth.ts that exports the config, with a comment saying to import it and pass it to NextAuth in app/api/auth/[...nextauth]/route.ts. The fix below is that pattern.

Why Windows shows the long version#

The short message is produced by Next.js's diagnostic formatter, which rewrites a diagnostic only when diagnostic.file?.fileName.startsWith(path.join(baseDir, distDir, 'types')). On Windows, path.join returns a backslash path, while TypeScript reports source file names with forward slashes: in the Windows reproduction, TypeScript 5.0.4 gave C:/…/appwin/app/page.tsx for a source file and path.join gave C:\…\appwin\.next\types, so the prefix test is false and the raw TypeScript chain is printed. A Linux control on a newer Node (the node:24-bookworm image, Next.js 13.4.3) still printed the short message, so the difference follows the operating system, not the Node version. The cause and the fix are identical on both systems.

Fix#

  1. Create a module for the options outside app/, here lib/auth.ts:
ts
import type { AuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
 
export const authOptions: AuthOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_ID as string,
      clientSecret: process.env.GOOGLE_SECRET as string,
    }),
  ],
};
  1. Make app/api/auth/[...nextauth]/route.ts import the options and export only the handlers:
ts
import NextAuth from "next-auth";
import { authOptions } from "@/lib/auth";
 
const handler = NextAuth(authOptions);
 
export { handler as GET, handler as POST };

The @/ prefix relies on a paths entry for @/* in tsconfig.json. Without one, use a relative import such as ../../../../lib/auth.

  1. Point every other import of the options at the new module. A server component that calls getServerSession now reads:
tsx
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
 
export default async function AccountPage() {
  const session = await getServerSession(authOptions);
  return <pre>{JSON.stringify(session, null, 2)}</pre>;
}

If nothing outside the route uses the options, the shorter fix from the third answer on the question also works: keep the object in route.ts and write const authOptions without export. Both were tested as the only change from the failing file.

Verify the fix#

Run npm run build again. With the options moved to lib/auth.ts, Next.js 13.4.3 on Linux passed the type check and went on to page generation: For next-auth v4 the same kind of gap is a missing NEXTAUTH_SECRET, which makes every auth endpoint answer with a 500 in production and sends sign-in to /api/auth/error; the next-auth /api/auth/error production fix covers setting it and triggering a new deployment.

text
- info Linting and checking validity of types...
- info Collecting page data...
- info Generating static pages (0/3)
- info Generating static pages (3/3)
- info Finalizing page optimization...

The same move, built natively on Windows, also passed. Verify with the real next build: the failing check lives in the .next/types files that the build generates.

One thing the passing build does not check: process.env.GOOGLE_ID as string is a type assertion, not a runtime guarantee. If the variable is missing on the host, the value is undefined and the build still succeeds. The postmortem on builds that pass while production breaks covers missing environment variables and the other gaps between a green build and a working deployment.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

Other exports that trip the same check#

  • The same object under another name. In issue 50870 the extra export was called handler, and its type was AuthOptions: the error read Property 'handler' is incompatible with index signature. Whatever the name, the property in that line is the export to move or un-export.
  • Segment config is allowed. export const dynamic = "force-dynamic" or export const runtime = "nodejs" in route.ts is part of the allowed list and does not cause this error.
  • typescript.ignoreBuildErrors is not a fix. It makes the build skip type checking for the whole project. The TypeScript page calls this option dangerous and asks you to run type checks elsewhere in your pipeline if you turn it on.

What changes on Next.js 16#

The same unmodified route.ts, with next-auth 4.24.15, failed on Next.js 15.4.11 and 15.5.27 with the short message, and built on 16.0.0 and 16.4.0. The 16.4.0 build generates a .next/types/validator.ts whose route-handler type lists the seven HTTP methods without an index-signature check, so an extra export no longer fails the type check in that run. The route.js reference has not added authOptions-style exports to the allowed list, though, and upgrading a major version to keep a misplaced export is a poor trade; a Next.js 16 upgrade brings its own build failures, such as the /_not-found prerender error. Moving the options to lib/auth.ts builds on every version tested.

How the versions were tested#

Tested on 11 October 2026 with the question's route.ts verbatim, a minimal app/layout.tsx and app/page.tsx, and a tsconfig.json with the Next.js plugin and an @/* path alias. Linux runs used the official node:18 Docker image for Next.js 13.4.3 (next-auth 4.22.1, TypeScript 5.0.4), node:24-bookworm for the 13.4.3 control, and node:22 for 15.4.11, 15.5.27, 16.0.0 and 16.4.0 (next-auth 4.24.15, TypeScript 5.9.3). The Windows runs used Windows 11 and Node 26.7.0 with the 13.4.3 dependency set. Each fix was applied as the only change from the failing file.

NextAuth has a second well-known build-time type error, on the Pages Router side: pageProps.session in _app.tsx, caused by a typing change in AppProps and covered in Property 'session' does not exist on type ''. For the error on this page, the rule to keep is short: a route.ts exports request handlers and segment config, and shared objects such as the NextAuth options live in a module of their own.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote