Custom _app and Custom _document in Next.js

Two of the most easily confused files in a Next.js application using the pages directory are _app and _document. This guide follows the Next.js 8 conventions available in February 2019.
They both sound central. They both sit close to the framework entry points. They both feel like places where "global" things might go. That is exactly why developers often blur their responsibilities together.
The truth is that they solve different problems.
If you understand that _app is about the React application and _document is about the surrounding HTML document, the distinction becomes much clearer.
_app wraps your page components
The custom App component lets you control how all page components are initialised.
In pages/_app.js, a small custom App can inherit the default page‑data handling and override rendering:
import React from 'react';
import App, { Container } from 'next/app';
class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<Component {...pageProps} />
</Container>
);
}
}
export default MyApp;Every page is rendered through this component.
That makes _app the natural place for application‑wide concerns such as:
- shared layout wrappers
- providers
- global styling through the configured styling solution
- page transition logic
_document is different
Custom _document is not for ordinary application logic. It is for controlling the overall HTML document that Next.js renders on the server.
In pages/_document.js, keep the framework's document pieces inside the HTML shell:
import React from 'react';
import Document, { Head, Main, NextScript } from 'next/document';
class MyDocument extends Document {
render() {
return (
<html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
export default MyDocument;This file controls the outer document shell, not the internal page tree.
Good uses for _app
_app often becomes the home for application‑level wrappers.
For example:
- a theme provider
- a global state provider
- common layout chrome
- global CSS imports when the project uses the CSS plugin
It is also the right place when every page should share some surrounding structure. In this example, SiteLayout is your own layout component:
import React from 'react';
import App, { Container } from 'next/app';
import SiteLayout from '../components/SiteLayout';
class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<SiteLayout>
<Component {...pageProps} />
</SiteLayout>
</Container>
);
}
}
export default MyApp;That is a natural fit because we are still inside the React application tree.
Good uses for _document
_document is for the HTML shell around the app:
- setting the
langattribute on<html> - customising the
<body> - injecting document‑level markup the server should output
- integrating certain CSS-in-JS or SSR requirements
The important point is that this file affects the outer document structure, not the component hierarchy inside the app.
Why putting the wrong thing in _document causes confusion
Because _document is rendered on the server, it is not the place for interactive UI logic, event handlers, or application state concerns.
Developers sometimes reach for it because it feels "global", but global is too vague a category. The right question is global to what?
If it is global to the HTML document, _document may fit.
If it is global to the running React application, _app is the better home.
The Main and NextScript pieces are not optional decoration
Inside _document, these pieces are essential.
<Main /> is where the page application content is rendered.
<NextScript /> is where Next.js injects the scripts it needs.
Removing or misplacing them usually breaks the application badly. That is a useful reminder that _document is infrastructure territory, not just another component file.
_app is a better place for shared UI
Suppose every page needs:
- a header
- a footer
- analytics wrappers
- a context provider
Those belong around page rendering in _app, not in _document.
Why? Because they are part of the UI tree the React application owns and updates. They are not raw document scaffolding.
Not Every Project Needs Heavy Customisation
Another small but useful point: just because these files exist does not mean every project should stuff them with logic.
A custom _app can be small.
A custom _document can be minimal.
There is no point using framework extension points just because they exist. They earn their keep when there is a real cross‑cutting responsibility to express.
Separate the React App from the HTML Shell
Custom _app and _document feel confusing only when both are treated as vague "global" buckets. In reality, they are for different layers of the system. _app is about the React application and the wrappers around page components. _document is about the outer HTML document rendered on the server.
Once that distinction is clear, both files become much easier to use correctly, and the application architecture stays cleaner for it.
Postscript
January 2020: Next.js 9.2 adds built‑in global CSS imports through pages/_app.js. Earlier projects need a CSS plugin for those imports. See the Next.js 9.2 release notes.
May 2023: The App Router is stable in Next.js 13.4. The pages directory covered here is now called the Pages Router. App Router projects use layouts and the Metadata API instead of these two custom files; see the App Router release explanation.
September 2026: A later project example: On a larger build, that split stops being an academic distinction. On the Nando’s UK & Ireland Replatform, keeping application concerns in _app and document concerns in _document was part of staying sane as the platform grew.