Markdown & MDX Content Authoring

Chapter 11
Markdown & MDX Content Authoring
Plain Markdown as the default, MDX for the genuinely rare case that needs a live component mid-content

Chapter 5 covered Content Collections as a structure. This chapter covers what actually goes inside them — plain Markdown for the vast majority of content, and MDX for the real, specific case where a piece of content needs a live, interactive component embedded directly in the prose.

Plain Markdown

--- title: 'Getting Started with Islands' publishDate: 2026-08-06 --- ## Why Islands Matter Astro ships zero JavaScript by default. Here's a code example: ```js const count = 0; ``` ### Key Points - No runtime by default - Interactivity is opt-in - Each island hydrates independently

Standard Markdown syntax — headings, lists, fenced code blocks — renders exactly as expected. Fenced code blocks get real syntax highlighting automatically, via Astro's own built-in Shiki integration — no separate highlighting library or configuration needed, unlike many other static site tools.

MDX: Markdown with Embedded Components

--- title: 'A Post With a Live Chart' publishDate: 2026-08-06 --- import SalesChart from '../../components/SalesChart.jsx'; Here's some regular Markdown text, same as always. <SalesChart client:visible /> More regular Markdown text continues right after the component.

.mdx files allow real import statements and real component tags directly inside otherwise-plain Markdown prose — requires the @astrojs/mdx integration (npx astro add mdx).

Still needs its own client directive
An embedded component inside MDX content doesn't hydrate automatically just because it's inside content — SalesChart above still needs client:visible (or another directive from Chapter 7) exactly the same as anywhere else in an Astro project. MDX changes where a component can be placed, not the rules governing whether it ships JavaScript.
Not the default choice
MDX is genuinely the exception, not the rule — the overwhelming majority of blog posts, docs pages, and articles need nothing beyond plain Markdown. Reach for MDX specifically when a piece of content needs a real, live component embedded mid-prose — not as a default file extension for every post.

Mixing .md and .mdx in One Collection

A single Content Collection can contain both .md and .mdx files side by side, as long as every entry — regardless of extension — satisfies the same Zod schema defined in src/content/config.ts (Chapter 5). getCollection() returns both kinds of entries together, with no special handling needed to distinguish them.

Markdown vs. MDX, Compared

Markdown (.md)MDX (.mdx)
Can embed live components?NoYes
Requires an integration?No, built inYes — @astrojs/mdx
Right forThe vast majority of prose contentThe genuine, specific case needing a live component mid-content

Coding Challenges

Challenge 1

Write a full Markdown blog post in a content collection with multiple headings, a list, and a fenced code block, and confirm it renders with proper syntax highlighting with zero extra configuration.

📄 View solution
Challenge 2

Convert that post to MDX and embed a real interactive island component (with a client directive) directly inside the prose, confirming both the text and the component render and work correctly.

📄 View solution
Challenge 3

Confirm a collection can mix .md and .mdx entries by adding one of each satisfying the same schema, and list both together via a single getCollection() call.

📄 View solution

Chapter 11 Quick Reference

  • Plain Markdown — the right default for the vast majority of content, built-in Shiki syntax highlighting
  • MDX (.mdx) — real imports and component tags inside Markdown prose, via @astrojs/mdx
  • Embedded components still need a client directive — MDX changes placement, not Chapter 7's own hydration rules
  • Not the default — MDX is for the specific case, not every post
  • Mixed collections.md and .mdx can coexist in one collection, same schema, same getCollection() call
  • Next chapter: Capstone — Building a Content-Driven Site