Based on the official Next.js documentation, Middleware is executed before rendering, including before layouts and pages. The documented execution order is:
- headers from next.config.js
- redirects from next.config.js
- Middleware (rewrites, redirects, etc.)
- beforeFiles (rewrites) from next.config.js
- Filesystem routes (public/, _next/static/, pages/, app/, etc.)
- afterFiles (rewrites) from next.config.js
- Dynamic Routes (/blog/[slug])
- fallback (rewrites) from next.config.js
This means Middleware should always run before your /app layout or any page/component is rendered, as long as the route matches your Middleware's matcher configuration. If your /app layout is being invoked without the session check from Middleware, possible reasons include:
- The Middleware matcher is not correctly targeting the /app route.
- There is a misconfiguration or bug causing Middleware not to run (see known issues below).
Important caveat:
Due to Partial Rendering and client-side navigation, layouts do not re-render on every route change. This means that if a user navigates client-side, the layout may not re-run, and thus, session checks in the layout may not be reliable for every navigation. Middleware, however, is only invoked on server-side navigations or full page reloads, not on all client-side transitions. This can lead to situations where the layout is rendered without a fresh Middleware check, especially during client-side navigation. The documentation explicitly warns against relying on layouts for auth checks for this reason, and recommends performing checks closer to your data source or in Middleware for initial access control Layouts and auth checks.