OMNI-CORE LogoOMNI-CORE
omni-mdxomni-3D (soon)Open SourceAbout
GitHubDocumentation
OMNI-CORE

Knowledge must flow freely to shape the future.

Ecosystem

  • omni-mdx
  • omni-3D

Resources

  • Documentation
  • Interactive Playground

Legal & Open Source

  • GitHub Organization
  • Notice

TOAQ GROUP © 2024 - 2026

Released under the MIT License.

Navigation

Getting Started

  • Introduction
    • Web & Next.js
    • Python Engine
    • Build from Source
  • Syntax Guide

Web Integration

  • Next.js Integration
  • Binary AST Transfer
  • Custom Components
  • Unified & Plugins Ecosystem Integration
    • Basic App Router
    • Advanced Rendering
    • Live Client Editor

Python

  • Introduction & Core Engine
    • Basic Parsing & Traversal
    • Advanced Analysis & RAG
    • Native Qt Rendering
    • HTML & Web Rendering
    • Basic Parsing
    • Advanced Analysis
    • HTML Rendering
    • Qt Rendering

Architecture & Core

    • Design Philosophy
    • The Rendering Pipeline
    • Lexing & Tokenization
    • AST Node Design
    • Math & JSX Handling
    • Protocol Specification
    • Zero-Copy Decoding
    • Memory Lifecycle
    • WASM Bindings (Browser)
    • Node.js Native Addons
    • Python Bindings (PyO3)
  • Security
    • Benchmarks
    • Fuzzing Results
Docs
Next.js Integration

Next.js & React Integration

Last Updated March 22, 2026

The @toaq-oss/omni-mdx package is the React/Next.js visual rendering engine of the TOAQ-oss MDX ecosystem. It consumes the ultra-fast Abstract Syntax Tree (AST) generated by our Rust core and transforms it into interactive, secure, and highly customizable React components.

Why This Exists

Most MDX pipelines run at the JS level and require client-side hydration for math, syntax highlighting, and custom components. This traditional approach causes several issues:

  • A large JS bundle sent to every visitor.
  • Math rendered on the client (flash of unstyled content).
  • Custom components that can’t be pure Server Components.

@toaq-oss/omni-mdx solves this by moving the parse step into Rust and the render step into React Server Components. The result is zero JS for content — everything is HTML by the time it reaches the browser.

Data Serialization & Caching

The AST generated by parseMdx is a standard JavaScript Object (POJO). This means it is 100% JSON-serializable. You can safely store the AST in Redis, a database, or use Next.js cache() without any performance penalty during retrieval.


Server Components (Recommended)

The most efficient way to use Omni-MDX is within Next.js App Router Server Components.

tsx
import { parseMdx, MDXServerRenderer } from "@toaq-oss/omni-mdx/server";
import { Note, Details }               from "@/components/mdx";

const COMPONENTS = { Note, Details };

export default async function ArticlePage({ params }) {
  const content = await getArticleContent(params.slug);
  const ast     = await parseMdx(content);

  return ;
}

Because parseMdx is async and runs on the server, it works naturally with generateStaticParams for Static Site Generation (SSG). At next build, Next.js calls parseMdx once per article and pre-renders everything to static HTML. The Rust parser never runs in the browser.


Live Editor (Client-Side)

For live MDX previews where the content changes directly in the browser, you can use the client renderer:

tsx
"use client";
import { MDXClientRenderer } from "@toaq-oss/omni-mdx/client";

export function LivePreview({ ast, components }) {
  return ;
}

The ast prop should be computed server-side and passed down, or computed client-side by calling a Route Handler that runs parseMdx.


Component Registry

You can map JSX tags found in your MDX directly to your own React components. Register components by name — the key matches the JSX tag in the MDX source:

ts
import { Note }    from "@/components/Note";    // can be a Server Component
import { Details } from "@/components/Details"; // can be a Server Component
import { Chart }   from "@/components/Chart";   // "use client" inside

const COMPONENTS = { Note, Details, Chart };

Server Components in the registry are rendered on the server with zero client JS. Client Components are hydrated normally.


Image Optimization

By default, Omni-MDX renders standard <img> tags. To use the Next.js Image component for automatic optimization (WebP, lazy loading), map it in your registry:

tsx
import Image from "next/image";

const COMPONENTS = {
  img: (props) => (
    {props.alt
  ),
};

Error Handling

Parse Errors

When generating the AST on the server, you can catch syntax issues using the custom MDXParseError class:

tsx
import { parseMdx, MDXParseError } from "@toaq-oss/omni-mdx/server";

try {
  const ast = await parseMdx(content);
} catch (e) {
  if (e instanceof MDXParseError) {
    console.error("MDX syntax error:", e.message);
    console.error("Source:", e.source);
  }
}

Component Boundaries

In MDXClientRenderer, every custom component is automatically wrapped in MDXErrorBoundary. If a component throws, the error is isolated — the rest of the document continues to render.


Math & KaTeX

Math is parsed natively in Rust. To maintain Zero JS for content, Omni-MDX outputs static HTML attributes (data-math).

  • Static Rendering: If you only need the layout, just import the CSS.
  • Interactive Hydration: Use MDXClientRenderer if you need complex KaTeX features in the browser.
tsx
// Required for any math rendering
import "katex/dist/katex.min.css";

Runtime Detection

The package auto-detects the environment and loads the appropriate backend without any configuration required.

  • Native .node execution: Supported on Node.js 18+ and Next.js (RSC).
  • WASM Fallback: Available across all environments, including Edge runtimes and the Browser.
Boosted by omni-mdx native node

On this page

  • Why This Exists
  • Data Serialization & Caching
  • Server Components (Recommended)
  • Live Editor (Client-Side)
  • Component Registry
  • Image Optimization
  • Error Handling
  • Parse Errors
  • Component Boundaries
  • Math & KaTeX
  • Runtime Detection
Edit this page on GitHub

Caught a typo or want to improve the docs? Submitting a PR is the best way to help!