Oliver White
6 May 2026 · 8 min read
In NextAuth v5, getServerSession() is gone — replaced by auth() with no arguments. The authOptions config moves to a top-level auth.ts file. Middleware no longer uses withAuth() — it wraps a handler that calls auth() directly. If you are upgrading from v4 or starting fresh on Next.js 14 App Router, these three changes affect every part of the auth integration.
In v4, your entire auth configuration lived inside app/api/auth/[...nextauth]/route.ts. In v5, the config moves to a top-level auth.ts file, and the route handler just re-exports the handlers. This separation matters because auth.ts can be imported by middleware and Server Components directly.
In v4, you called getServerSession() and passed it your authOptions. In v5, you call auth() — no arguments needed — because it reads the config from auth.ts automatically. This works in Server Components, Server Actions, API routes, and middleware.
| Context | v4 pattern | v5 pattern |
|---|---|---|
| Server Component | getServerSession(authOptions) | auth() |
| API Route | getServerSession(req, res, authOptions) | auth() |
| Middleware | withAuth() wrapper from next-auth/middleware | Import auth from auth.ts, wrap handler |
| Client Component | useSession() from next-auth/react | useSession() — unchanged |
The v5 middleware integration is where most people hit issues. You don't use withAuth() anymore. Instead, you export a default function that calls auth() and wraps your own middleware logic. This means you can apply security headers, redirects, and auth checks in the same file:
The auth() call in middleware adds latency because it validates the session token on every matched request. Keep the matcher pattern specific — exclude static assets, images, and any route that doesn't need auth context. The pattern above shaves ~40ms off static asset responses.
By default, session.user only has name, email, and image. To add id and role (which you need for admin checks), you extend the types. Without this, TypeScript will complain every time you access session.user.role:
Built with this methodology
In NextAuth v5, getServerSession() is replaced by auth(), authOptions moves to auth.ts, and the middleware uses a wrapping pattern instead of withAuth(). This covers all three changes with working code for Next.js 14 App Router.
From the build log