Next.js App Router Error: Invariant Expected App Router to Be Mounted
Problem Statement
When migrating from Next.js 12 to 13 using the new /app directory structure, you may encounter the error:
Uncaught Error: invariant expected app router to be mountedThis error typically occurs when:
- Using the App Router (new
/appdirectory) - Accessing
useRouterfromnext/navigation - The Next.js router context is unavailable or improperly initialized
The error originates from this code in Next.js:
function useRouter() {
const router = useContext(AppRouterContext);
if (router === null) {
throw new Error('invariant expected app router to be mounted');
}
return router;
}Key symptoms:
- Error occurs only in
/appdirectory components - Router functionality is broken
- Issue doesn't affect
/pagesdirectory components - Error appears during migration from Next.js 12 to 13
Solutions
1. Add Required HTML/Body Tags to Root Layout
The most common solution involves fixing your root layout file (app/layout.tsx). Next.js requires a specific HTML structure:
export default function RootLayout({ children }: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}Documentation Requirement:
"The root layout must define
<html>and<body>tags since Next.js does not automatically create them."
– Next.js Layouts Documentation
WARNING
Your layout file must directly return <html> and <body> tags without any wrapping components:
// ❌ Problem: Body is wrapped in provider
export default function RootLayout({ children }) {
return (
<html>
<AuthProvider>
<body>{children}</body> {/* Context wraps body */}
</AuthProvider>
</html>
);
}// ✅ Solution: Keep body tag clean
export default function RootLayout({ children }) {
return (
<html>
<body>
<AuthProvider>{children}</AuthProvider> {/* Inside body */}
</body>
</html>
);
}2. Handle Parallel Routes Correctly
When using parallel routes, ensure a default.js file exists at the root of each slot to provide fallback content:
app/
layout.js
@sidebar/
default.js # Required even if empty!
page.js3. Fix Router Import Conflicts
Use consistent router imports based on your routing strategy:
// App Router (/app directory)
import { useRouter } from 'next/navigation';
// Pages Router (/pages directory)
import { useRouter } from 'next/router';4. Testing Environment Fixes
When using testing tools like Jest:
jest.mock('next/navigation'); // Add to test setup fileFor Storybook (@storybook/nextjs):
const preview = {
parameters: {
nextjs: { appDirectory: true }, // Enable App Router
},
};5. Client-Component Migration
Shared components between /app and /pages may need 'use client' directive:
'use client'; // Add to top of shared component file
import { useRouter } from 'next/navigation';
function SharedComponent() {
const router = useRouter();
// ...
}Additional Considerations
- Do not manipulate DOM directly: Avoid
document.querySelectorin layout components - Avoid client-side rendering for root layout: Keep
app/layout.jsas a Server Component by default - Check file placement: Component-specific loading states (
loading.js) should reside in page directories, not app root
Explanation of Underlying Cause
The useRouter hook relies on the AppRouterContext which is only mounted when:
- The App Router is properly initialized
- Required DOM elements (
<html>,<body>) exist in root layout - Components are correctly placed in the App Router structure
When migrating from Pages Router to App Router, the structural requirements change significantly. The App Router requires explicit HTML structure declarations that weren't necessary in previous versions, leading to this error when omitted.
Recommended Migration Strategy
- Create a proper
app/layout.jswith<html>and<body> - Move existing layout logic inside the
<body>tag - Verify all
useRouterimports usenext/navigation - Check for parallel route requirements and missing
default.jsfiles - Test functionality progressively using Next.js's migration guide
Official Resources
By addressing these structural requirements and import patterns, you can resolve the "invariant expected app router to be mounted" error and successfully migrate to Next.js 13's App Router.