Migrating a Documentation Site from Nextra 2 to Nextra 4

Migration Guide from Nextra 2 to Nextra 4

* This page contains promotional content

Introduction

Nextra 4 was released and I tried to move a site built with Nextra 2 over to Nextra 4, but there were so many changes that the upgrade did not go well.
So instead of updating the Nextra 2 project, I created a Nextra 4 project and decided to migrate the Nextra 2 project into the Nextra 4 project.

In this article I go through the changes required when migrating from Nextra 2 to Nextra 4.

1. Router change: Pages Router → App Router

The biggest change is the router.

VersionRouterDirectory
Nextra 2Pages Routerpages/
Nextra 4App Routerapp/

Nextra 4 supports only the Next.js App Router.
MDX files under pages/ have to be moved to app/.

2. Configuration changes in next.config

Nextra 2

const withNextra = require('nextra')({
  theme: 'nextra-theme-docs',
  themeConfig: './theme.config.tsx',
})

module.exports = withNextra({})

Nextra 4

import nextra from "nextra";

const withNextra = nextra({});

export default withNextra({
  turbopack: {
    resolveAlias: {
      "next-mdx-import-source-file": "./mdx-components.js",
    },
  },
});

Main changes:

  • The theme and themeConfig options are gone
  • Changed from CommonJS to the ESM import form
  • The resolveAlias setting is required when using Turbopack

3. Migrating the theme configuration: theme.config.tsxapp/layout.tsx

Nextra 2: theme.config.tsx

export default {
  logo: <span>My Docs</span>,
  project: { link: 'https://github.com/...' },
  footer: { text: 'MIT 2024' },
}

Nextra 4: app/layout.tsx

import { Footer, Layout, Navbar } from "nextra-theme-docs";
import { Head } from "nextra/components";
import { getPageMap } from "nextra/page-map";
import "nextra-theme-docs/style.css";

const navbar = <Navbar logo={<b>My Documentation</b>} />;
const footer = <Footer>MIT {new Date().getFullYear()} © My Documentation.</Footer>;

export default async function RootLayout({ children }) {
  return (
    <html lang="ja" dir="ltr" suppressHydrationWarning>
      <Head />
      <body>
        <Layout
          navbar={navbar}
          pageMap={await getPageMap()}
          docsRepositoryBase="https://github.com/..."
          footer={footer}
        >
          {children}
        </Layout>
      </body>
    </html>
  );
}

Main changes:

  • The theme configuration is passed as props of the Layout component
  • pageMap is obtained with the getPageMap() function
  • The CSS has to be imported explicitly (nextra-theme-docs/style.css)

4. mdx-components.js is now required

In Nextra 4, an mdx-components.js file at the project root has become mandatory.

import { useMDXComponents as getThemeComponents } from "nextra-theme-docs";

const themeComponents = getThemeComponents();

export function useMDXComponents(components) {
  return {
    ...themeComponents,
    ...components,
  };
}

Without this file you get the following error:

Module not found: Can't resolve 'next-mdx-import-source-file'

5. Format change for _meta files

Nextra 2: _meta.json (JSON format)

{
  "index": "Introduction",
  "getting-started": "Getting Started"
}

Nextra 4: _meta.js (ESM format)

export default {
  index: "Introduction",
  "getting-started": "Getting Started",
};

The file name has also changed from _meta.json to _meta.js.

6. Placement rules for MDX files

VersionExample path
Nextra 2pages/docs/index.mdx
Nextra 4app/docs/page.mdx or content/docs/index.mdx

With the App Router you either follow the page.mdx naming convention or use the content/ directory.

7. Changes to import paths

PurposeNextra 4
Theme componentsnextra-theme-docs
Banner, Head, and so onnextra/components
getPageMapnextra/page-map
Theme CSSnextra-theme-docs/style.css

8. Static export configuration

When exporting as a static site, the following settings are required in next.config.ts.

export default withNextra({
  output: "export",  // output static files into the out/ directory
  images: {
    unoptimized: true,  // disable image optimization for static export
  },
});

Once you set output: "export", the build result is written into the out/ directory when you run npm run build.

9. Configuring search (Pagefind)

Nextra 4 uses Pagefind for search.
You have to generate the search index after the build.

Installation

npm install -D pagefind

package.json configuration

{
  "scripts": {
    "build": "next build",
    "postbuild": "pagefind --site out --output-path out/_pagefind"
  }
}

The postbuild script runs automatically after npm run build finishes.

Points to note:

  • --site out: specifies the directory the static export goes to
  • --output-path out/_pagefind: where the search index is written
  • If you have not set output: "export", use --site .next/server/app

When search does not work

  1. Check that output: "export" is set
  2. Check that the --site path in postbuild is out
  3. Check that the out/_pagefind/ directory is created after the build

Summary

ItemNextra 2Nextra 4
RouterPages RouterApp Router
Theme configurationtheme.config.tsxapp/layout.tsx
MDX componentsNot neededmdx-components.js required
Meta file_meta.json_meta.js
nextra configurationtheme, themeConfigEmpty object or mdxOptions
Search engineFlexSearch (built in)Pagefind (needs configuration)
Build output.next/out/ (with static export)