Skip to content
Blume
Esc
↑↓navigate↵open⌘Jpreview
On this page

Remote MDX

Fetch Markdown and MDX over HTTP from a GitHub repository or a raw URL with the mdxRemote() source, rendered with every Blume component.

The built-in mdxRemote() adapter fetches raw .md/.mdx over HTTP. Enumerate files either from a GitHub repo subtree (github) or explicitly against a raw base URL (url + files):

import { defineConfig } from "blume";
import { filesystem, mdxRemote } from "blume/sources";

export default defineConfig({
  content: {
    sources: [
      filesystem({ root: "docs" }),
      // The docs/ subtree of acme/sdk, mounted under /sdk
      mdxRemote({
        prefix: "sdk",
        github: { owner: "acme", repo: "sdk", ref: "main", path: "docs" },
      }),
    ],
  },
});

To list the files yourself, point url at a raw base URL:

mdxRemote({
  prefix: "sdk",
  url: "https://raw.githubusercontent.com/acme/sdk/main/docs",
  files: ["intro.mdx", "guide.mdx"],
});

include (default ["**/*.{md,mdx}"]) filters the files by their path under path, the way a filesystem() source’s include does: a pattern starting with ! excludes what it matches (["**/*.mdx", "!drafts/**"]). With github, the source lists the repository’s whole tree at ref and keeps the files under path. If nothing is under path at that ref, the source reads no pages and warns with BLUME_SOURCE_PATH_MISSING. GitHub caps the listing (100,000 entries or 7 MB for the whole repository, whatever path is), and past it the source warns with BLUME_SOURCE_TRUNCATED: list the files with url and files instead.

A relative link between remote files ([Errors](./02-errors.mdx)) lands on the page the linked file publishes at, with its ordering prefix dropped from the route. It does on the rendered page, in the page’s Markdown copy and llms-full.txt, and in what the assistant reads, and blume validate checks it the same way.

A private repo’s token is read from the GITHUB_TOKEN environment variable. It is never inlined into your config or generated output, and it is only ever sent to GitHub’s own hosts (api.github.com, raw.githubusercontent.com), never to a custom url base. A public repo works without it. With github, the adapter declares the variable, so blume dev and blume build warn BLUME_MISSING_SECRET when it’s unset: the file listing goes through GitHub’s API, which allows 60 unauthenticated requests an hour. A raw url reads files only, so nothing warns up front; when GitHub refuses a file with a 401, 403, or 404 while GITHUB_TOKEN is unset, the warning for the skipped file says the variable isn’t set.

A file written to read on GitHub often opens with a # Heading, while Blume renders the page’s title as its <h1>. When a remote page’s first line is an h1 that matches its front matter title, or the front matter sets no title, the heading is dropped and its text is the title, so the page shows one <h1>. A first heading that differs from title stays.

Remote pages are rendered with full MDX-plus-component fidelity: their bodies are materialized into a hidden staging directory and rendered through Astro alongside your local docs, so callouts, tabs, and every other Blume component keep working.

Like every remote source, fetched pages are cached for offline builds and refreshed with blume sync — see Caching and offline builds.

Build one docs portal from multiple GitHub repositories uses it to pull each repository’s docs folder into one site, pinned to a release that moves only when you change it.

Last updated on

Was this page helpful?