NextAuth: Property 'session' does not exist on type '{}'
Reproduced on Next.js 12.3.4, 13.0.0 and 16.4.0: why the session prop broke in _app.tsx, the one-line generic that fixes it, and why the d.ts override only seems to work.
A Next.js app that wires NextAuth.js into pages/_app.tsx exactly as the NextAuth getting-started page shows can stop compiling with a type error on the session prop. The cause is a change to the AppProps type in Next.js, not NextAuth, and the fix is one generic argument.
TL;DR#
- Cause: from Next.js 12.3.0 to 12.3.4,
AppPropsdefaulted its generic to{}and typedpagePropswith it. ReadingpageProps.session(or destructuringsessionout of it) is then a property access on an empty object type. - Fix: tell
AppPropswhatpagePropsholds:AppProps<{ session?: Session | null }>, withSessionimported fromnext-auth. - Not the fix: adding
sessionto theComponenttype. That changes the wrong prop. - From Next.js 13.0.0 the default is
anyand the error disappears, but so does the type check onsession.
The error as next build prints it, reproduced on Next.js 12.3.4 with TypeScript 4.8.4:
info - Linting and checking validity of types...
Failed to compile.
./pages/_app.tsx:6:41
Type error: Property 'session' does not exist on type '{}'.Running the TypeScript compiler on its own gives the same error with its code:
pages/_app.tsx(6,41): error TS2339: Property 'session' does not exist on type '{}'.This is the error behind the Stack Overflow question "(NextAuth) Type error: Property 'session' does not exist on type ''", asked in September 2022 and viewed more than 24,000 times.
Why it happens#
The NextAuth.js v4 example exposes the session context by destructuring it out of pageProps in pages/_app.jsx:
import { SessionProvider } from "next-auth/react"
export default function App({
Component,
pageProps: { session, ...pageProps },
}) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
)
}That is JavaScript. In a .tsx file the props are annotated with AppProps from next/app, and what pageProps is typed as depends on the Next.js version:
- In Next.js 12.2.5,
pagePropswas hard-coded toany, so any property access compiled. - PR #38867, "fix(ts): use
AppProps's generic forpageProps", merged on 26 August 2022, madepagePropstake the type of theAppPropsgeneric. The generic's default stayed{}. The merge commit is in the v12.3.0 tag and not in v12.2.5, which matches the release the accepted answer names. - PR #41264, "fix(ts): relax
AppPropsto not require generic", merged on 7 October 2022, changed the default toany. Its description says #38867 had made thepagePropsshape "always require" a generic, "since the default{}will throw a TS error if you try accessing any property". That commit is in the v13.0.0 tag; the published 12.3.4 package still ships the{}default.
So with Next.js 12.3.x, AppProps with no argument means pageProps: {}, and session is not a property of {}. It makes no difference whether the code reads pageProps.session or destructures { session, ...pageProps }: both were reproduced, and both fail with the same TS2339 error.
The Next.js custom App documentation states what pageProps is at runtime: "pageProps is an object with the initial props that were preloaded for your page by one of our data fetching methods, otherwise it's an empty object." TypeScript cannot know which pages return a session prop, so the shape has to come from you.
Why extending the Component type does not help#
The question's first attempt added session to the Component type:
export interface CustomAppProps extends AppProps {
Component: NextComponentType & { auth?: boolean; session?: Session };
}On Next.js 12.3.4 this still fails with Property 'session' does not exist on type '{}', at the destructuring of pageProps. The error is about pageProps; Component is a different prop.
Fix: give AppProps the shape of pageProps#
- Import the
Sessiontype fromnext-authand pass the shape ofpagePropsas the generic ofAppProps. The destructuring from the NextAuth example now type-checks unchanged:
// pages/_app.tsx
import type { Session } from "next-auth";
import { SessionProvider } from "next-auth/react";
import type { AppProps } from "next/app";
export default function MyApp({
Component,
pageProps: { session, ...pageProps },
}: AppProps<{ session?: Session | null }>) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
);
}Both the ? and the | null are deliberate. In next-auth v4, getServerSession is declared to return a promise of the session or null (source), so a page that returns its result as a prop can pass null. And pages that return no session prop at all leave it undefined in _app.tsx. SessionProvider accepts both. The NextAuth client documentation says that passing the session page prop lets you "avoid checking the session twice", and that "this only works on pages where you provide the correct pageProps" (client docs).
- Return the session from the pages that need it. The NextAuth.js v4 Next.js configuration page recommends
getServerSessioningetServerSidePropsand shows a page returning it as a prop:
// pages/dashboard.tsx
import type { GetServerSideProps } from "next";
import { getServerSession } from "next-auth/next";
import { authOptions } from "./api/auth/[...nextauth]";
export const getServerSideProps: GetServerSideProps = async (context) => {
const session = await getServerSession(context.req, context.res, authOptions);
if (!session) {
return { redirect: { destination: "/", permanent: false } };
}
return { props: { session } };
};
export default function Dashboard() {
return <p>Signed in</p>;
}This page, the API route exporting authOptions and the _app.tsx above type-check together and build on Next.js 12.3.4.
- If
_app.tsxalso needs other page props, add them to the same object type, for exampleAppProps<{ session?: Session | null; title?: string }>. Keep everything that pages pass throughpagePropsin that one type.
Verify the fix#
Run the type checker on its own, then the build:
npx tsc --noEmit
npx next buildOn Next.js 12.3.4, the version with the error, the file above passes tsc with exit code 0, and next build gets past the type step to the compiled output:
info - Linting and checking validity of types...
info - Creating an optimized production build...
info - Compiled successfullyOne 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.
The types/next.d.ts override only seems to work#
A second answer on the Stack Overflow thread copies a types/next.d.ts file from the NextAuth TypeScript example repository, which redeclares AppProps inside declare module "next/app" with a session field on pageProps. Copied into a Next.js 12.3.4 project, it does make the original _app.tsx compile. Turning library checking back on shows why:
types/next.d.ts(6,8): error TS2300: Duplicate identifier 'AppProps'.The file declares a second AppProps type alias, which TypeScript reports as a duplicate. The error only stays hidden because skipLibCheck skips checking every .d.ts file, and the tsconfig that Next.js writes for a project suggests skipLibCheck: true (writeConfigurationDefaults.ts). That example repository has also been archived on GitHub. The generic in the fix needs no declaration file and no compiler option to stay quiet.
After upgrading to Next.js 13 or later#
On Next.js 13.0.0 and on 16.4.0 (with TypeScript 7.0.2), all three failing versions of _app.tsx compile without the generic, because pageProps is now any. The current Next.js source still declares AppProps<P = any>.
That any turns the type check off rather than satisfying it. A deliberately wrong line shows the difference on Next.js 16.4.0:
const probe: number = pageProps.session; // deliberately wrong typeWith plain AppProps, tsc exits 0. With AppProps<{ session?: Session | null }>, it catches the mistake:
pages/_app.tsx(5,9): error TS2322: Type 'Session | null | undefined' is not assignable to type 'number'.So the generic is worth keeping after an upgrade. If the upgrade also moves the project to a newer TypeScript major, other errors can show up at the same time; the TypeScript migration notes for Next.js and Supabase projects list what changed in the compiler defaults.
When the project uses the App Router#
All of the above concerns the Pages Router, where _app.tsx and pageProps exist. The App Router has no pageProps. The NextAuth example page notes that SessionProvider "requires a client component and therefore cannot be put inside the root layout", so it goes in a separate file marked "use client" that the layout renders. If the boundary between server and client files is unclear, use client vs use server in Next.js explains what each directive actually marks.
How this was reproduced#
Each version of pages/_app.tsx was compiled in a throwaway node:22-bookworm container on 7 October 2026, with next-auth 4.24.15: on Next.js 12.3.4 with TypeScript 4.8.4 (the plain AppProps, the destructured version and the Component-type attempt all fail with TS2339; the generic passes, under tsc and next build, alongside a getServerSideProps page and the auth API route), on Next.js 13.0.0 (all pass), and on Next.js 16.4.0 with React 19.3.0 and TypeScript 7.0.2 (all pass; the probe above). The AppProps defaults were also read from the published type definitions of each version.
If the build now gets past the types but fails while collecting page data, look at what getServerSideProps returns next to the session: props must be JSON-serialisable, and a Date object breaks that, as covered in the "[object Date]" cannot be serialized as JSON fix. And if the team is weighing whether to stay on NextAuth at all, Clerk vs Better Auth vs Supabase vs Auth.js compares the options for a Next.js project.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix: "[object Date]" Cannot Be Serialized as JSON
A Date prop cannot go straight from getStaticProps to the page — convert it first, or the page will not build.
Next.js 'Module not found: Can't resolve': 6 Fixes
Module not found errors only in production? Learn why Next.js builds fail after deploy and get 6 proven fixes that work on Vercel, AWS, and other platforms.
Fix Next.js revalidatePath Not Working in Server Actions
Your Server Action mutates data but the page shows stale values until you hard-refresh. `revalidatePath` is one of those APIs that "succeeds" while doing nothing. Here are the six reasons it no-ops, with the exact fix for each — including a URL served through a rewrite and a second page that reads the same tagged data.


