Custom App & Document in Pages Router

5 questions found

What is the purpose of the custom App component in the Pages Router?

Beginner
The custom App component, defined in pages/_app.js, wraps every page in your application, making it the perfect place to add global styles, shared layouts, or context providers that need to be available across the entire site.
// pages/_app.js
import '../styles/globals.css';

export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}
Real-world example A website imports its global CSS file once inside _app.js, ensuring consistent styling like fonts and colors are applied across every single page in the application.

Common follow-ups: Can you add a global navigation bar inside the custom App component?;Does the custom App component exist in the App Router as well?

Layouts & Templates;Styling in Next.js (CSS Modules Tailwind & Styled Components)

What is the custom Document component used for in the Pages Router?

Beginner
The custom Document component, defined in pages/_document.js, controls the initial HTML structure of your page, such as the html and body tags, and is the right place to add things like custom fonts, a language attribute, or third party scripts that need to load in the head or body.
// pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}
Real-world example A multilingual website sets the correct lang attribute on the html tag inside its custom Document component, helping search engines and screen readers understand the page's primary language.

Common follow-ups: What is the difference between the custom App and custom Document components?;Can you use React state or hooks inside the custom Document component?

Metadata API & SEO Optimization;Accessibility

Why can you not use React hooks like useState inside the custom Document component?

Intermediate
The custom Document component only renders on the server to generate the initial HTML shell, and it never re-renders on the client, so hooks that manage interactive client side state have no purpose there and are not supported in this file.
// This would not work as expected in _document.js
// because Document only runs once on the server
function Document() {
  // useState is not appropriate here
}
Real-world example A developer tries adding a useState hook inside _document.js to track a loading flag, but quickly learns this file only builds the static page shell and moves that logic into _app.js instead.

Common follow-ups: Where should client side interactive logic be placed instead?;What lifecycle does the Document component follow compared to a normal page?

Client Components & Hydration;Layouts & Templates

How would you add global error tracking or analytics scripts using the custom App and Document components together?

Advanced
You typically add analytics initialization code inside the custom App component using a useEffect so it runs on route changes, while adding the actual third party script tag inside the custom Document component's head section so it loads early as part of the initial HTML.
// pages/_document.js
<Head>
  <script src="https://analytics.example.com/script.js" async />
</Head>

// pages/_app.js
useEffect(() => {
  trackPageView(router.pathname);
}, [router.pathname]);
Real-world example A retail website loads its analytics script in _document.js so it starts early, while tracking each page view inside _app.js whenever the user navigates to a new page.

Common follow-ups: Should analytics scripts be loaded with next/script instead of a plain script tag?;How do you avoid duplicate tracking events on the first page load?

Third-Party Script Optimization;Metadata API & SEO Optimization

If a project is migrating from the Pages Router to the App Router, what happens to the custom App and Document components?

Intermediate
In the App Router, the custom App and Document components are replaced by the root layout file, typically app/layout.js, which combines their responsibilities into a single file where you define the html and body tags and wrap your pages with any global providers or styles.
// app/layout.js replaces both _app.js and _document.js
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}
Real-world example A team migrating an older Next.js project combines the logic from their old _app.js and _document.js files into a single new root layout file as part of adopting the App Router.

Common follow-ups: Can you run both the Pages Router and App Router in the same project during a migration?;What other Pages Router specific files need to be replaced during migration?

Layouts & Templates;Routing (App/Pages Router)