Astro MDX integration: components inside your Markdown

In over a decade of building content systems, the piece that breaks first is almost always the bridge between raw content and interactive UI. We spent years hacking around it with WordPress shortcodes or giant JSON blobs. The Astro MDX integration is the first version of that bridge that does not feel like a band-aid on a bullet wound.

Markdown was a great idea for writing less markup, and it has always had a ceiling. Ask it for a custom call-to-action button or a real data table inside a post and it gives up. You end up hand writing HTML inside a .md file, and six months later nobody wants to touch it. MDX is the way out.

Why MDX beats raw HTML in Markdown

MDX is a superset of Markdown that lets you use components, Astro or React or Svelte, inside your content. The payoff is less boilerplate, which is usually where maintenance work goes to die.

In a normal Astro project the Astro MDX integration puts logic and prose in the same file without a fight. You can import a Svelte chart into a Markdown file and pass it data as props. No shortcode parser, no regex hacks holding the whole thing together.

Implementation patterns

There are a couple of patterns I keep coming back to in production. Which one fits depends on whether you are building a single landing page or a documentation site with hundreds of entries.

1. Direct component imports

The fastest way in is to treat the MDX file as a component. That works well for static pages that still need to do some real work. The import looks like this:

---
import MDXContent from '../content/legal/privacy-policy.mdx';
---

<article class="prose">
  <MDXContent />
</article>

2. The Content Collections workflow

Once you are past a few hundred posts, use Content Collections. It is the only thing that keeps your frontmatter from decaying into a pile of undefined errors. When you set up src/content/config.ts, make sure the glob pattern picks up the mdx extension as well.

import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const blog = defineCollection({
  loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content/blog" }),
  schema: z.object({
    title: z.string(),
    pubDate: z.date(),
  }),
});

export const collections = { blog };

Worth knowing: you can pass global components into <Content />, so you stop importing the same <Image /> and <Button /> at the top of every MDX file. On the subject of tooling, I wrote up my take on using AI assistants in production too.

The gotchas: formatting and RSS

Two friction points with the Astro MDX integration are worth knowing about before you commit a whole site to it.

  • Prettier and ESLint still trip over MDX, and your auto-formatter will happily mangle the JSX sitting inside your Markdown. Keeping the JSX simple is most of the fix. When a component block gets hairy, move it into its own .astro file.
  • The standard Astro RSS package will not render MDX for you, because feed readers want plain HTML and have no idea what a JSX component is. You need Astro’s experimental container API or a custom renderer to flatten the MDX into stringified HTML before it goes into the feed.

If this kind of work is eating your dev hours, hand it over. I have been wrestling with WordPress since the 4.x days and have spent the last few years on these modern stacks.

Worth it, with caveats

MDX lets content live inside the component ecosystem instead of next to it. The tooling around linting and RSS is still rough, but for me the time the Astro MDX integration saves is worth the setup you have to do around those two problems.

So stop hand writing HTML in your Markdown. Turn on MDX, build out your component library, and the site gets easier to maintain from there. If you run into a performance question or a weird edge case, reach out. Odds are I have already broken it and fixed it twice.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.