Markdown and MDX Content

Purpose and Scope

Astro treats content authoring as a first-class part of building a site. Plain Markdown is the default path for text-heavy pages such as blog posts and documentation, and official guidance describes it as GitHub Flavored Markdown with optional YAML or TOML frontmatter for metadata. MDX extends that workflow when authors need JSX expressions, variables, and components inside Markdown. Markdoc is another structured content language, and this page focuses on how the repository implements the Markdoc integration while positioning it alongside Markdown, MDX, and content collections.

The practical decision for a project is not only which file extension to use, but which authoring contract the content should follow. Use Markdown when prose plus frontmatter is enough. Use MDX when content should embed component syntax directly. Use content collections when a set of entries shares a schema and should be queried, rendered, validated, and typed through Astro’s content APIs. Use Markdoc when you want a configurable tag and node system backed by Markdoc schemas, custom components, and integration-managed rendering behavior.

Sources: packages/integrations/markdoc/package.json, packages/integrations/markdoc/src/index.ts

Relevant Source Files

  • packages/integrations/markdoc/tsconfig.build.json - Shows that the Markdoc package builds against Astro, internal helpers, the shared remark package, and Astro Prism, which explains its placement in the content and Markdown-adjacent toolchain.
  • packages/integrations/markdoc/src/config.ts - Defines the public Markdoc configuration helpers, schema typing, component helper, exported Markdoc instance, and customized node map.
  • packages/integrations/markdoc/src/options.ts - Defines the integration options accepted by the Markdoc integration: allowHTML, ignoreIndentation, and typographer.
  • packages/integrations/markdoc/components/index.ts - Re-exports the Astro Renderer component used by the Markdoc package component entrypoint.
  • packages/integrations/markdoc/src/index.ts - Implements the default integration function, Astro lifecycle hooks, content entry type registration, Vite SSR externals, and development server restart behavior for config changes.
  • packages/integrations/markdoc/package.json - Declares the @astrojs/markdoc package metadata, exports, scripts, dependencies, peer dependency on Astro, Node engine, and published files.

Authoring Model: Markdown, MDX, Collections, and Markdoc

Markdown files can live anywhere under src/, and Markdown files in src/pages/ become pages automatically according to the official guide. Imported Markdown exposes content and frontmatter to .astro components, while content collections provide a more scalable API for groups of related entries. Collections add schemas, validation, editor type support, and optimized query and render helpers. This is the recommended model when a project has many similarly shaped entries, such as blog posts, product descriptions, recipes, or documentation pages.

MDX fits a different authoring need. The official MDX integration allows .mdx pages and lets authors use variables, JSX expressions, and components inside Markdown content. In practice, that makes MDX useful when the content itself must compose UI elements. Markdoc is closer to a configured content language: rather than arbitrary JSX, it exposes explicit tags, nodes, render targets, and schemas. That distinction matters for teams that want a controlled content vocabulary with reusable rendering components and validation rules.

The Markdoc package identifies itself as @astrojs/markdoc and describes its purpose as adding Markdoc support to an Astro site. Its package metadata marks it as an Astro integration and Astro component package, exports a default integration entrypoint, and exposes configuration, runtime, component, Prism, and Shiki subpaths. The build configuration also references the shared Markdown remark package and Astro Prism, making the package part of Astro’s broader Markdown-oriented content pipeline rather than an isolated renderer.

Sources: packages/integrations/markdoc/package.json, packages/integrations/markdoc/tsconfig.build.json

Markdoc Integration Flow

The default export from packages/integrations/markdoc/src/index.ts is markdocIntegration(options?: MarkdocIntegrationOptions): AstroIntegration. When Astro runs the astro:config:setup hook, the integration records the active Astro config, loads the project’s Markdoc config, registers a content entry type, and updates Vite SSR settings. The content entry type is important because it lets Markdoc participate in Astro’s content system instead of being only a standalone transform. The Vite update externalizes @astrojs/markdoc/prism and @astrojs/markdoc/shiki for SSR.

During development, the integration also listens to the dev server watcher in astro:server:setup. If a changed file matches one of the supported Markdoc config filenames, the server restarts. This makes configuration edits behave like other project-level build changes: Astro reloads the integration state rather than trying to patch a live configuration graph. For content authors, the result is a content format that can be configured centrally and still participate in the normal Astro development loop.

A typical manual setup follows the same integration pattern used by official Astro integrations. Install the package, import it in astro.config.mjs, and add it to integrations. Markdoc-specific options are passed when the integration function is called. The exact behavior of parsing and rendering is delegated to the integration’s content entry type and configuration loader, while the visible public surface remains the integration function and exported configuration helpers.

import { defineConfig } from 'astro/config';
import markdoc from '@astrojs/markdoc';
 
export default defineConfig({
  integrations: [markdoc({ typographer: true })],
});

Sources: packages/integrations/markdoc/src/index.ts, packages/integrations/markdoc/src/options.ts

Configuration and Component Rendering API

The Markdoc configuration helper is defined in packages/integrations/markdoc/src/config.ts. defineMarkdocConfig(config) returns the supplied config and gives projects a typed place to define Markdoc tags, nodes, context, and extensions. AstroMarkdocConfig omits the raw Markdoc tags and nodes shape and replaces them with Astro-aware schema definitions whose render value may be a component configuration, an Astro component default export, or a string. It also supports an extends array of resolved Markdoc configs, allowing configuration composition.

The component(pathnameOrPkgName, namedExport?) helper is the bridge between Markdoc schema render targets and Astro component resolution. It returns a ComponentConfig with a type of package or local, a path, an optional named export, and an internal marker symbol. The helper classifies package names by checking whether the path is relative or absolute. A non-relative, non-absolute value is treated as an npm package name; relative and absolute paths are treated as local component references.

The same module re-exports the Markdoc implementation as Markdoc and defines nodes by spreading Markdoc’s default nodes and replacing or extending heading behavior with Astro’s heading ID support. The component entrypoint in packages/integrations/markdoc/components/index.ts exports Renderer, so consumers can import rendering support through the package’s ./components export. Together, these APIs let a project define a controlled content grammar and map that grammar to Astro-rendered output.

Sources: packages/integrations/markdoc/src/config.ts, packages/integrations/markdoc/components/index.ts, packages/integrations/markdoc/package.json

Compact Reference

AreaPublic nameSource-level contract
IntegrationmarkdocIntegration(options?)Default export returning an AstroIntegration; registers hooks for astro:config:setup and astro:server:setup.
OptionsMarkdocIntegrationOptionsSupports allowHTML?: boolean, ignoreIndentation?: boolean, and typographer?: boolean.
Config helperdefineMarkdocConfig(config)Returns an AstroMarkdocConfig for typed project configuration.
Component helpercomponent(pathnameOrPkgName, namedExport?)Produces a marked ComponentConfig for package or local component render targets.
Config exports@astrojs/markdoc/configPackage subpath for Markdoc configuration types and helpers.
Syntax highlighting helpers@astrojs/markdoc/prism, @astrojs/markdoc/shikiExported package subpaths and Vite SSR externals registered by the integration.
Renderer component@astrojs/markdoc/componentsRe-exports Renderer from the package component entrypoint.
Runtime exports@astrojs/markdoc/runtime, @astrojs/markdoc/runtime-assets-configRuntime subpaths declared in package exports.

The package contract is intentionally split between integration setup, author configuration, component rendering, and optional highlighting helpers. That split mirrors how content projects evolve: configuration belongs in a project-level Markdoc config, rendering belongs in Astro components, and the integration owns registration with Astro’s content and Vite systems. For Markdown and MDX authors moving into Markdoc, the key shift is that component usage is declared through Markdoc schema and helper configuration rather than written directly as JSX in every document.

Sources: packages/integrations/markdoc/package.json, packages/integrations/markdoc/src/config.ts, packages/integrations/markdoc/src/index.ts

Next Steps

Start with plain Markdown for pages and small content sets, then introduce content collections when repeated frontmatter and query logic need validation and type safety. Add MDX when writers need JSX-style component composition directly inside Markdown files. Choose Markdoc when a site needs a more governed authoring language, explicit tag and node schemas, shared rendering components, and integration-managed handling inside Astro’s content system. For implementation work in this repository, begin with the Markdoc integration entrypoint, then read the configuration helpers and package exports to understand the supported public surface.

Related pages: Content Collections, Content Loaders, Markdown and Content Integrations, Astro Modules Reference