notebook-mdx

Framework Integration

Integrate notebook-mdx with popular documentation frameworks

Framework Integration

Learn how to integrate notebook-mdx with popular documentation frameworks. Get your Jupyter notebooks rendering beautifully in your documentation site.

🚀 General Setup

Installation

npm install notebook-mdx

Basic Configuration

notebook-mdx requires two main components:

  1. Server-side: Remark plugin for processing notebook directives
  2. Client-side: React components for rendering notebooks
// Import the server plugin (includes remark-directive automatically)
import { remarkNotebook } from 'notebook-mdx/server';

// Import client components (one spread, all components included)
import { notebookComponents } from 'notebook-mdx/client';

Usage in MDX

Once configured, you can embed notebooks using the directive syntax:

# My Tutorial

Basic notebook embedding:
:::notebook{file="./examples/basic.ipynb"}
:::

Show specific cells:
:::notebook{file="./examples/analysis.ipynb" cells="1-5"}
:::

Hide code, show only output:
:::notebook{file="./examples/visualization.ipynb" hideCode}
:::

With custom description:
:::notebook{file="./examples/demo.ipynb" showCellNumbers}
This notebook demonstrates data analysis techniques.
:::

Configuration Options

// Custom base directory for notebooks
[remarkNotebook, {
  baseDir: './content/notebooks',
}]

// Custom component name
[remarkNotebook, {
  componentName: 'CustomNotebookRenderer',
}]

Development Experience

notebook-mdx strives to provide a good development experience with several key benefits:

🔄 Development Workflow

Current state: Changes to .ipynb files don't automatically trigger hot module reload. Here's the current workflow:

  1. Edit your notebook in Jupyter/VSCode
  2. Trigger refresh by either:
    • Resave the MDX file that contains the notebook directive
    • Make a small edit to the MDX file and save
    • Restart the dev server if the above doesn't work

🚧 Hot Module Reload (Coming Soon)

Full HMR support for notebooks is a priority on our roadmap! Soon you'll be able to:

  • Edit notebooks in Jupyter/VSCode → See changes immediately in your docs
  • Modify notebook cells → Updates appear instantly
  • No workarounds needed → True hot reload experience

⚡ Fast Rendering

  • Build-time processing - Notebooks are parsed during build for optimal runtime performance
  • Optimized re-renders - Only changed cells update, not the entire notebook
  • Zero hydration issues - Components render consistently between server and client

🛠️ Developer-Friendly

  • TypeScript support - Full type safety and IntelliSense
  • Clear error messages - Helpful debugging information when notebooks fail to load
  • Component inspection - Works seamlessly with React DevTools

📚 Fumadocs

Status: ✅ Fully Supported

Fumadocs is a modern documentation framework built on Next.js.

Configuration

1. Update your source configuration

// source.config.ts
import { remarkNotebook } from 'notebook-mdx/server';
import { defineConfig, defineDocs } from 'fumadocs-mdx/config';

export const { docs, meta } = defineDocs({
  dir: 'content/docs',
});

export default defineConfig({
  mdxOptions: {
    remarkPlugins: [
      remarkNotebook, // Handles everything — no separate remark-directive needed
    ],
  },
});

2. Update MDX components

// mdx-components.tsx
import defaultMdxComponents from "fumadocs-ui/mdx";
import type { MDXComponents } from "mdx/types";
import { notebookComponents } from "notebook-mdx/client";

export function getMDXComponents(components?: MDXComponents): MDXComponents {
  return {
    ...defaultMdxComponents,
    ...components,
    ...notebookComponents,
  } as MDXComponents;
}

Advanced Configuration

Custom Base Directory

// source.config.ts
export default defineConfig({
  mdxOptions: {
    remarkPlugins: [
      [remarkNotebook, {
        baseDir: './content/notebooks',
      }],
    ],
  },
});

Custom Component Name

// source.config.ts
export default defineConfig({
  mdxOptions: {
    remarkPlugins: [
      [remarkNotebook, {
        componentName: 'CustomNotebookRenderer',
      }],
    ],
  },
});

Project Structure

my-fumadocs-site/
├── app/
│   ├── layout.tsx
│   └── docs/
├── content/
│   ├── docs/
│   │   ├── index.mdx
│   │   ├── tutorial.mdx
│   │   └── examples/
│   │       ├── basic.ipynb          # Notebooks alongside MDX
│   │       └── advanced.ipynb
│   └── notebooks/                   # Or separate notebook directory
│       ├── data-analysis.ipynb
│       └── visualization.ipynb
├── source.config.ts
└── package.json

Best Practices for Fumadocs

  1. Organize notebooks alongside content:

    content/docs/
    ├── tutorial/
    │   ├── index.mdx
    │   ├── basics.ipynb
    │   └── advanced.ipynb
  2. Use descriptive file names:

    :::notebook{file="./data-analysis-pandas.ipynb"}
    :::
  3. Leverage Fumadocs features:

    <Callout type="info">
    The following notebook demonstrates the core concepts:
    
    :::notebook{file="./core-concepts.ipynb" cells="1-3"}
    :::
    </Callout>

📚 Next.js with MDX

Status: ✅ Fully Supported

Installation

npm install notebook-mdx @next/mdx

Configuration

// next.config.mjs
import { remarkNotebook } from 'notebook-mdx/server';
import createMDX from '@next/mdx';

const withMDX = createMDX({
  options: {
    remarkPlugins: [
      remarkNotebook,
    ],
  },
});

/** @type {import('next').NextConfig} */
const nextConfig = {
  pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
};

export default withMDX(nextConfig);

mdx-components.tsx

import type { MDXComponents } from 'mdx/types';
import { notebookComponents } from 'notebook-mdx/client';

export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    ...components,
    ...notebookComponents,
  };
}

⚠️ Turbopack Compatibility

@next/mdx is not compatible with Turbopack (the default bundler in Next.js 15+). You must use webpack:

# Dev
next dev --webpack

# Or set in package.json
"dev": "next dev --webpack"

Usage

Works with both Pages Router (pages/) and App Router (app/) in Next.js.

📖 Nextra

Status: ✅ Supported

notebook-mdx works with Nextra v4 on Next.js 15.

Installation

npm install notebook-mdx nextra nextra-theme-docs

Configuration

// next.config.mjs
import nextra from 'nextra'
import { remarkNotebook } from 'notebook-mdx/server'

const withNextra = nextra({
  mdxOptions: {
    remarkPlugins: [remarkNotebook],
  },
})

export default withNextra({})

Component registration

// mdx-components.jsx
import { useMDXComponents as useNextraMDXComponents } from 'nextra/mdx-components'
import { notebookComponents } from 'notebook-mdx/client'

export function useMDXComponents(components) {
  return useNextraMDXComponents({
    ...notebookComponents,
    ...components,
  })
}

⚠️ Turbopack incompatibility

Same as Next.js + @next/mdx — Turbopack silently drops remark plugins (Next.js 15) or throws a hard error (Next.js 16). Always run without Turbopack:

next dev --webpack
# or in package.json: "dev": "next dev --webpack"

⚠️ Next.js 16 not supported

Nextra v4 + Next.js 16 has an RSC/SWC bug unrelated to notebook-mdx. Use Next.js 15.

📘 Docusaurus

Status: ✅ Supported

notebook-mdx works with Docusaurus v3 using its built-in MDX and remark pipeline.

Installation

npm install notebook-mdx

Configuration

1. Add remark plugin to your preset

// docusaurus.config.js
import { remarkNotebook } from 'notebook-mdx/server';

export default {
  presets: [
    ['@docusaurus/preset-classic', {
      docs: {
        remarkPlugins: [remarkNotebook],
      },
      blog: {
        remarkPlugins: [remarkNotebook],
      },
    }],
  ],
};

2. Register MDX components via swizzling

Docusaurus uses a "swizzle" pattern to extend MDX components. Create or update src/theme/MDXComponents.js:

// src/theme/MDXComponents.js
import MDXComponents from '@theme-original/MDXComponents';
import { notebookComponents } from 'notebook-mdx/client';

export default {
  ...MDXComponents,
  ...notebookComponents,
};

3. Use in your MDX files

---
title: My Tutorial
---

# Data Analysis

:::notebook{file="./example.ipynb"}
:::

Project Structure

my-docusaurus-site/
├── docs/
│   ├── tutorial.mdx
│   └── examples/
│       └── example.ipynb      # Notebooks alongside content
├── src/
│   └── theme/
│       └── MDXComponents.js   # Component registration
└── docusaurus.config.js

📙 VitePress

Status: ❌ Not Supported

VitePress uses markdown-it (not remark/unified) and Vue 3 (not React). notebook-mdx remark plugins cannot be used in VitePress's pipeline.

Supporting VitePress would require a separate Vue component library and a markdown-it plugin — a significant effort with a different architecture. If you need VitePress support, open an issue to express interest.

📕 GitBook

Status: 🚧 Planned

GitBook integration is under consideration:

  • Block-based notebook rendering
  • Collaborative editing support
  • Version control integration

📗 Astro

Status: ✅ Supported

notebook-mdx works with Astro via @astrojs/mdx and @astrojs/react.

Installation

npm install notebook-mdx @astrojs/mdx @astrojs/react

Configuration

// astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import react from '@astrojs/react';
import { remarkNotebook } from 'notebook-mdx/server';

export default defineConfig({
  integrations: [
    react(),
    mdx({
      remarkPlugins: [remarkNotebook],
    }),
  ],
});

Component registration

Astro lowercases MDX component names when resolving them, so you must use notebookComponentsAstro (with lowercase keys) instead of notebookComponents:

---
// src/pages/my-doc.mdx
---
import { notebookComponentsAstro } from 'notebook-mdx/client';

export const components = notebookComponentsAstro;

# My Doc

:::notebook{file="./example.ipynb"}
:::

⚠️ Per-page component registration

Unlike Next.js or Fumadocs where components are registered globally, Astro requires you to export components from each MDX page that uses notebooks.

📘 Gatsby

Status: ✅ Supported

notebook-mdx works with Gatsby v5 + gatsby-plugin-mdx, but requires a specific remark-directive version due to a unified version mismatch.

Installation

npm install notebook-mdx gatsby-plugin-mdx gatsby-source-filesystem
npm install remark-directive@2   # Must be v2 — Gatsby uses @mdx-js/mdx@2 (unified@10), remark-directive@3+ requires unified@11

⚠️ Use remarkNotebookDirective, not remarkNotebook

remarkNotebook internally bundles remark-directive@4 which will crash in Gatsby. You must use remarkNotebookDirective with remark-directive@2 explicitly:

Configuration

// gatsby-config.mjs
import { fileURLToPath } from 'url'
import { dirname, resolve } from 'path'
import remarkDirective from 'remark-directive'              // v2 installed above
import { remarkNotebookDirective } from 'notebook-mdx/server'

const __dirname = dirname(fileURLToPath(import.meta.url))

const config = {
  plugins: [
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'pages',
        path: resolve(__dirname, 'src/pages'),  // Required for gatsby-plugin-mdx
      },
    },
    {
      resolve: 'gatsby-plugin-mdx',
      options: {
        mdxOptions: {
          remarkPlugins: [remarkDirective, remarkNotebookDirective],
        },
      },
    },
  ],
}

export default config

Component registration

Gatsby uses wrapRootElement in both gatsby-browser.js and gatsby-ssr.js:

// gatsby-browser.js (and gatsby-ssr.js — same content)
import React from 'react'
import { MDXProvider } from '@mdx-js/react'
import { notebookComponents } from 'notebook-mdx/client'

export const wrapRootElement = ({ element }) => (
  <MDXProvider components={notebookComponents}>{element}</MDXProvider>
)

🔧 Custom Framework Integration

If you're using a different framework or want to integrate notebook-mdx manually:

Requirements

Your framework needs:

  1. MDX support with remark plugins
  2. React/JSX rendering capability
  3. File system access during build

Integration Steps

  1. Follow the General Setup section above
  2. Configure your framework's MDX processor to use the remark plugins
  3. Add the React components to your MDX component mapping

Need Help?

If you're working on integration with a framework not listed here:

📊 Framework Comparison

FrameworkStatusDifficultyNotes
Fumadocs✅ ReadyEasyFull support
Next.js + MDX✅ ReadyEasyUse --webpack (Turbopack incompatible with @next/mdx)
Docusaurus✅ ReadyEasyFull support
Nextra✅ ReadyEasyUse --webpack; Next.js 15 only
Astro✅ ReadyEasyUse notebookComponentsAstro for component registration
Gatsby✅ ReadyMediumUse remarkNotebookDirective + remark-directive@2 (unified@10)
VitePress❌ Not supportedUses markdown-it + Vue, incompatible architecture
GitBook🤔 EvaluatingHardBlock system
  1. Start with Fumadocs if you're building a new documentation site
  2. Use Next.js + MDX for existing Next.js applications
  3. Use Nextra for Next.js with a built-in docs theme
  4. Use Astro or Docusaurus for other React-based doc sites
  5. Request integration for your preferred framework via GitHub issues

Have questions about framework integration? Check our GitHub Discussions or open an issue.