Zero dependencyMDX readyBuilt for SSRCross-framework

    Markdown that renders 5× faster.

    Intlayer ships its own Markdown engine. No dependency, MDX included, parsed on the server, and rendered natively in React, Next.js, Vue, Svelte, Solid, Preact and Angular. You never have to pick a renderer again.

    markdown-file.content.md
    ---key: my-markdown-contentdescription: My content---# My contentHere an example of markdown content

    When the locale front-matter field is omitted, Intlayer uses your configured default locale. You can maintain your entire content in a single markdown file without locale identifiers.

    Example of file structure:
    content
    └── markdown-file.content.md
    markdown-file.en.content.md
    ---key: my-markdown-contentdescription: My contentlocale: en---# My contentHere an example of markdown content

    The locale front-matter field defines the locale of the content. It is optional. If not provided, Intlayer will use the default locale, which is also used as fallback locale if no translation is available for a specific locale.

    Example of file structure:
    content
    ├── markdown-file.en.content.md
    ├── markdown-file.fr.content.md
    └── markdown-file.es.content.md
    article.content.ts
    import { md, file, t, type Dictionary } from 'intlayer';export default {  key: 'article',  content: {    body: t({      en: md(file('./article.en.md')),      fr: md(file('./article.fr.md')),    }),  },} satisfies Dictionary;

    Declare Markdown directly inside a TypeScript, ESM, or JSON dictionary using the md() and file() functions, pairing translations with full type safety.

    Example of file structure:
    content
    ├── article.content.ts
    ├── article.en.md
    └── article.fr.md
    No dependency
    MDX components
    Typed frontmatter
    Purged when unused

    5× the throughput of markdown-to-jsx

    The parser was rewritten around a cached rule precedence and an incremental lookbehind, so a document is walked once instead of being re-scanned rule by rule. Same Markdown, same output, a fraction of the work.

    Intlayer
    markdown-to-jsx

    Relative parse and render throughput, higher is better.

    0 kB

    shipped when your app declares no Markdown node — the renderer is purged at build time.

    ~55 kB

    lazily fetched parser chunk, loaded behind Suspense so it never blocks the first paint.

    0

    runtime dependencies — nothing to audit, nothing to keep in sync.

    One engine instead of a shopping list

    Every project ends with the same chore: weigh markdown-to-jsx against marked, remark and MDX, wire the winner in, then discover it does not do MDX, that its types are loose, or that its plugin chain breaks on the client. Intlayer makes that choice for you.

    Capability
    Intlayer
    markdown-to-jsx
    marked
    remark / rehype
    @mdx-js
    MDX components
    Supported
    Not supported
    Not supported
    Partial, or through extra packages
    Supported
    Type-safe nodes and overrides
    Supported
    Not supported
    Partial, or through extra packages
    Partial, or through extra packages
    Partial, or through extra packages
    React and Next.js output
    Supported
    Supported
    Not supported
    Partial, or through extra packages
    Supported
    Vue, Svelte, Solid, Preact, Angular
    Supported
    Not supported
    Partial, or through extra packages
    Partial, or through extra packages
    Partial, or through extra packages
    Server parse, client render, no re-parse
    Supported
    Not supported
    Partial, or through extra packages
    Supported
    Partial, or through extra packages
    Configured without a plugin chain
    Supported
    Supported
    Partial, or through extra packages
    Not supported
    Not supported
    Typed frontmatter metadata
    Supported
    Not supported
    Not supported
    Partial, or through extra packages
    Partial, or through extra packages
    Zero runtime dependencies
    Supported
    Supported
    Supported
    Not supported
    Not supported
    Removed from the bundle when unused
    Supported
    Not supported
    Not supported
    Not supported
    Not supported
    SupportedPartial, or through extra packagesNot supported
    • remark and rehype can do most of it, but through a plugin chain you assemble yourself — and one that does not always behave the same in the browser as on the server.
    • markdown-to-jsx renders React only, and marked hands you an HTML string. For Vue, Svelte, Solid or Angular there is no equivalent to reach for.
    • None of them hands you typed frontmatter: you stack a content layer on top, or parse the metadata yourself.

    The same node, in every framework

    A Markdown node is turned into the native output of the framework it lands in — JSX, a VNode, or an HTML string. Svelte, Solid and Angular are first-class, not afterthoughts.

    Parse on the server, render on the client

    Parsing and rendering are two separate steps. parseMarkdown produces a serialisable AST on the server, the browser receives it as JSON, and every renderer accepts it as-is — so the document is never walked twice.

    On the server
    The document is parsed once, into JSON you can cache, stream or store.
    route.server.ts
    import { parseMarkdown } from 'react-intlayer/markdown';export const loader = async () => {  // Walked once, on the server  const ast = parseMarkdown('## My title\n\nLorem Ipsum');  return Response.json({ content: ast });};
    On the client
    Renderers take a raw string or an AST, so the browser only paints.
    Page.tsx
    import { useLoaderData } from 'react-router';import { MarkdownRenderer } from 'react-intlayer/markdown';export default function Page() {  const { content } = useLoaderData();  // No re-parsing in the browser  return <MarkdownRenderer content={content} />;}

    Set it once, refine it per node

    Declare your components on the provider and every Markdown node in the app picks them up. When one node needs to differ, use() overrides only that node — no plugin chain, no separate build step.

    Global, for the whole app
    AppProvider.tsx
    import { MarkdownProvider } from 'react-intlayer/markdown';export const AppProvider = ({ children }) => (  <MarkdownProvider    components={{      h1: ({ children }) => <h1 className="text-3xl">{children}</h1>,      MyButton: (props) => <button {...props} />, // MDX component    }}  >    {children}  </MarkdownProvider>);
    Local, for one node
    Article.tsx
    import { useIntlayer } from 'react-intlayer';const Article = () => {  const { body } = useIntlayer('article');  // Overrides the provider, for this node only  return body.use({    h1: ({ children }) => <h1 className="text-primary">{children}</h1>,  });};

    use() wins over the provider, the provider wins over the default renderer.

    Typed frontmatter, no content layer

    The frontmatter of a Markdown file is parsed with the document and exposed on the node as a typed metadata object. The editorial fields you used to reach for a content layer for are simply there, autocompleted.

    article.en.content.md
    ---key: articlelocale: entitle: Shipping i18n Markdownauthor: aymericzip---# Shipping i18n MarkdownHere an example of markdown content.
    Article.tsx
    const { body } = useIntlayer('article');body.metadata.title; // 'Shipping i18n Markdown'body.metadata.author; // 'aymericzip'body.value; // the raw Markdown string
    The same engine also parses HTML

    html() nodes go through the same pipeline: tags are mapped to your own components, with the same typing and the same override rules.

    See HTML content
    Code-Based i18n

    Type-safe translations that live in your repo.

    Declare content alongside your components in TypeScript or JavaScript. Intlayer generates types automatically, giving you autocompletion, validation, and instant feedback. No more missing keys, context switching, or broken implementations.

    AI CLI Tool

    Automate translations from your terminal.

    The CLI to audit, fill, and translate JSON & Markdown with AI.

    Run `npx intlayer fill` to detect missing keys and generate translations using OpenAI, Claude, or local models. Keep your Git history clean and your types safe.

    Intlayer TMS

    Stop paying per word. Automate with AI.

    The open-source & self-hosted alternative to Crowdin & Lokalise. Built for modern developer workflows.

    Manage translations directly in your code or via the visual editor. Leverage AI to translate instantly. Collaborate with your team without seat limits.

    Headless CMS

    Bridge your local code with remote content.

    Manage multilingual content with zero overhead. Intlayer allows you to interconnect local dictionaries with remote management, enabling Live Sync for hot updates without rebuilding. Use webhooks for CI/CD, manage feature flags, and let the Auto-Translation AI (WIP) handle the rest.

    Feature Flags

    Toggle features instantly. No deploy required.

    Intlayer dictionaries are more than just text. Use them to declare logic, styles, and configuration objects. With Live Sync, you can toggle features on or off, change UI themes, and update app behavior in real-time directly from the CMS.

    AB testing

    Your Playground for Product Experiments.

    Be the first to explore Intlayer's new AI-driven A/B Testing beta, built to boost discoverability and guide smarter product decisions. Test anything in real time, from copy and design to entire features, and let the data show you what truly works.

    Built by the Community

    Meet the amazing contributors who make Intlayer possible.

    Stop choosing a Markdown renderer

    It is already in Intlayer: dependency free, MDX capable, SSR ready, typed end to end, and gone from your bundle when you do not use it.