Custom _app and Custom _document in Next.js

Hero image for Custom _app and Custom _document in Next.js. Image by Krakograff Textures.
Hero image for 'Custom _app and Custom _document in Next.js.' Image by Krakograff Textures.

Two of the most easily confused files in a traditional Next.js application are _app and _document.

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.

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.


_app wraps your page components

The custom App component lets you control how all page components are initialised.

At a simple level, it looks like this:

import type { AppProps } from 'next/app';const MyApp = ({ Component, pageProps }: AppProps): JSX.Element => {  return <Component {...pageProps} />;};export default MyApp;

Every page is rendered through this component.

That makes _app the natural place for applicationwide concerns such as:

  • shared layout wrappers
  • providers
  • global styles
  • 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.

A custom document usually looks more like this:

import Document, {  Head,  Html,  Main,  NextScript,} from 'next/document';class MyDocument extends Document {  public render(): JSX.Element {    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.


The Easiest Distinction

If the feature belongs to the React application users interact with after hydration, _app is probably the place.

If the feature belongs to the serverrendered HTML document itself, _document may be the place.

That simple split prevents most confusion.


Good uses for _app

_app often becomes the home for applicationlevel wrappers.

For example:

  • a theme provider
  • a global state provider
  • common layout chrome
  • imported global CSS

It is also the right place when every page should share some surrounding structure:

const MyApp = ({ Component, pageProps }: AppProps): JSX.Element => {  return (    <SiteLayout>      <Component {...pageProps} />    </SiteLayout>  );};

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 lang attribute on <html>
  • customising the <body>
  • injecting documentlevel 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.


_document is more about shape than behaviour

That is another helpful way to think about it.

_document shapes the static outer HTML.

_app shapes how the application behaves and is composed.

Once you keep those two jobs separate, the files stop looking interchangeable.


Keep the Responsibilities in Their Own Lane

If a team starts placing providers, layout logic, and runtime concerns into _document, the project becomes harder to reason about because it is ignoring the separation the framework is trying to give you.

Likewise, if documentlevel HTML concerns are scattered into page files instead of handled centrally where appropriate, the application becomes less consistent.

Next.js gives us these two entry points precisely so those responsibilities can stay distinct.


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 crosscutting 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.


Categories:

  1. Development
  2. Front‑End Development
  3. Guides
  4. JavaScript
  5. Next.js