Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/shuding/nextra/llms.txt

Use this file to discover all available pages before exploring further.

Nextra’s file-system routing is great for content you manage locally, but many projects need to pull MDX from an external source — a CMS, a GitHub repository, or a remote API. Nextra provides first-class support for this pattern through the compileMdx function and the MDXRemote component, which together let you fetch, compile, and render remote Markdown at build time with full support for syntax highlighting, Nextra components, and table of contents extraction.

Core APIs

compileMdx

Compiles a raw MDX string into executable JavaScript on the server side. Imported from nextra/compile.

MDXRemote

A React component that renders a pre-compiled MDX string in the browser. Imported from nextra/mdx-remote.

fetchFilePathsFromGitHub

Fetches a list of file paths from a GitHub repository tree for use in dynamic routes. Imported from nextra/fetch-filepaths-from-github.

convertToPageMap

Converts a flat list of file paths into a Nextra page map structure. Imported from nextra/page-map.

Basic Remote Content Page

The simplest remote content pattern fetches Markdown from a URL, compiles it, and renders it — all at request time (or build time with generateStaticParams).
app/remote/page.tsx
import { compileMdx } from 'nextra/compile'
import { MDXRemote } from 'nextra/mdx-remote'

export default async function Page() {
  const response = await fetch(
    'https://raw.githubusercontent.com/owner/repo/main/docs/intro.mdx'
  )
  const markdown = await response.text()
  const rawJs = await compileMdx(markdown)
  return <MDXRemote compiledSource={rawJs} />
}
compileMdx returns a Promise<string> — the compiled JavaScript string. Pass this string directly to the MDXRemote component via its compiledSource prop. MDXRemote evaluates it safely at render time.

Dynamic Routes from a GitHub Repository

For documentation hosted on GitHub, Nextra provides fetchFilePathsFromGitHub to discover available files, and convertToPageMap plus mergeMetaWithPageMap to build the sidebar structure.
1
Fetch available file paths from GitHub
2
Use fetchFilePathsFromGitHub to query the GitHub API and write a JSON cache of available MDX file paths. This is typically run as a prebuild script so the data is available at build time:
3
import { fetchFilePathsFromGitHub } from 'nextra/fetch-filepaths-from-github'

await fetchFilePathsFromGitHub({
  user: 'graphql-hive',
  repo: 'graphql-eslint',
  branch: 'main',
  docsPath: 'website/src/pages/docs/',
  outputPath: './remote-paths.json'
})
4
The function calls https://api.github.com/repos/{user}/{repo}/git/trees/{branch}?recursive=1, filters to the specified docsPath, and writes the list of .md/.mdx paths to outputPath.
5
Build a page map for the sidebar
6
Use convertToPageMap to turn the flat file path list into a Nextra page map tree, then use mergeMetaWithPageMap to customize sidebar titles and ordering:
7
import { notFound } from 'next/navigation'
import { compileMdx } from 'nextra/compile'
import { evaluate } from 'nextra/evaluate'
import {
  convertToPageMap,
  mergeMetaWithPageMap,
  normalizePageMap
} from 'nextra/page-map'

const user = 'graphql-hive'
const repo = 'graphql-eslint'
const branch = '34b722a2a520599ce06a4ddcccc9623b76434089'
const docsPath = 'website/src/pages/docs/'

const filePaths = [
  'configs.mdx',
  'custom-rules.mdx',
  'getting-started.mdx',
  'getting-started/parser-options.mdx',
  'getting-started/parser.mdx',
  'index.mdx'
]

const { mdxPages, pageMap: _pageMap } = convertToPageMap({
  filePaths,
  basePath: 'docs'
})

// Customize sidebar titles and ordering
const eslintPageMap = mergeMetaWithPageMap(_pageMap[0]!, {
  index: 'Introduction',
  'getting-started': {
    items: {
      index: 'Overview',
      'parser-options': '',
      parser: ''
    }
  },
  configs: '',
  'custom-rules': ''
})

export const pageMap = normalizePageMap(eslintPageMap)
8
Fetch and render content for each route
9
Add the page component that fetches each file’s content from GitHub at build time and renders it with compileMdx and evaluate:
10
type PageProps = Readonly<{
  params: Promise<{ slug?: string[] }>
}>

export default async function Page(props: PageProps) {
  const params = await props.params
  const route = params.slug?.join('/') ?? ''
  const filePath = mdxPages[route]

  if (!filePath) {
    notFound()
  }

  const response = await fetch(
    `https://raw.githubusercontent.com/${user}/${repo}/${branch}/${docsPath}${filePath}`
  )
  const data = await response.text()
  const rawJs = await compileMdx(data, { filePath })
  const { default: MDXContent, toc, metadata } = evaluate(rawJs, components)

  return (
    <Wrapper toc={toc} metadata={metadata}>
      <MDXContent />
    </Wrapper>
  )
}

export function generateStaticParams() {
  return Object.keys(mdxPages).map(route => ({
    slug: route ? route.split('/') : undefined
  }))
}
11
Add the remote page map to your layout
12
Merge the remote page map into the main Nextra page map in your app/layout.tsx so the remote pages appear in the sidebar and mobile navigation:
13
import { getPageMap } from 'nextra/page-map'
import { pageMap as remoteDocsPageMap } from './docs/[[...slug]]/page'

// Inside your layout component:
const pageMap = [...(await getPageMap()), remoteDocsPageMap]

MDXRemote Component API

The MDXRemote component accepts three props:
import { MDXRemote } from 'nextra/mdx-remote'

<MDXRemote
  compiledSource={rawJs}          // required: string from compileMdx()
  components={{ MyChart: Chart }} // optional: extra React components for MDX
  scope={{ version: '3.0.0' }}   // optional: variables accessible in MDX
/>
PropTypeDescription
compiledSourcestringRequired. The compiled JS string returned by compileMdx().
componentsMDXComponentsOptional map of name → component available inside the MDX.
scopeobjectOptional variables available as identifiers inside the MDX content.

compileMdx Function API

compileMdx accepts the raw MDX string and an optional options object, and returns a Promise<string>:
import { compileMdx } from 'nextra/compile'

const rawJs = await compileMdx(rawMdxString, {
  filePath: 'docs/intro.mdx',        // helps with error messages and format detection
  defaultShowCopyCode: true,          // show copy button on code blocks
  codeHighlight: true,                // enable Shiki syntax highlighting
  readingTime: false,                 // inject reading time metadata
  staticImage: false,                 // optimize local images
  mdxOptions: {
    remarkPlugins: [myRemarkPlugin],  // custom remark plugins
    rehypePlugins: [myRehypePlugin],  // custom rehype plugins
  }
})
compileMdx is a server-only function. Never call it from a Client Component or in browser-executed code. Always use it inside Server Components, getStaticProps, or route handlers.

fetchFilePathsFromGitHub API

import { fetchFilePathsFromGitHub } from 'nextra/fetch-filepaths-from-github'

await fetchFilePathsFromGitHub({
  user: 'owner',           // GitHub username or org
  repo: 'repository',      // Repository name
  branch: 'main',          // Branch, tag, or commit SHA
  docsPath: 'docs/',       // Path prefix to filter files by
  outputPath: './paths.json' // Where to write the JSON result
})
The function writes a JSON file at outputPath containing:
{
  "user": "owner",
  "repo": "repository",
  "branch": "main",
  "docsPath": "docs/",
  "filePaths": ["intro.mdx", "guide/setup.mdx"]
}
The GitHub API has rate limits for unauthenticated requests (60/hour). For CI environments, set a GITHUB_TOKEN environment variable to increase the limit to 5,000/hour. fetchFilePathsFromGitHub logs an error and exits gracefully if the rate limit is exceeded.

Full Working Example

The SWR site example in the Nextra repository demonstrates the complete remote content pattern with internationalization, dynamic routes, and sidebar integration.

Build docs developers (and LLMs) love