How to export constants, functions, metadata, and components from your MDX files so other parts of your app can use them.
Exports let your MDX files share data with the rest of your app. Your content file isn't just a document anymore — it's a module. You can export metadata, config objects, helper functions, whatever you need. Other files can import those values and use them.
This is how you build things like blog listing pages, sitemaps, and navigation — by pulling structured data out of your content files.
Export Syntax in MDX
Standard JavaScript export syntax works in MDX. Most people put exports at the top, but they can go anywhere:
export const title = "My Amazing Article"
export const author = "Jane Developer"
# {title}
Written by {author}
Exported values work two ways: you can use them inside the same MDX file as variables, and other files can import them.
Export Placement Rules
{/* Exports can be at the top */}
export const publishDate = '2024-03-15'
# Article Title
{/* Exports can be between content blocks */}
export const relatedLinks = ['/guide', '/api']
Some paragraph content here.
{/* Exports can be at the bottom */}
export const lastModified = '2024-03-20'
Best Practice: Put exports at the top for discoverability, unless they logically belong near specific content sections.
Exporting Constants
Constants are the most common export type in MDX files.
Simple Values
export const title = "Getting Started with MDX"
export const description = "A complete beginner's guide to MDX"
export const version = "2.0.0"
export const draft = false
export const readingTime = 8 // minutes
Configuration Objects
export const metadata = {
title: "API Reference",
description: "Complete API documentation for v3",
author: "Engineering Team",
publishDate: "2024-06-01",
lastUpdated: "2024-06-15",
category: "documentation",
tags: ["api", "reference", "v3"]
}
export const seo = {
ogImage: "/images/api-reference-og.png",
canonical: "https://docs.example.com/api",
noIndex: false
}
export const navigation = {
prev: { title: "Installation", href: "/docs/install" },
next: { title: "Authentication", href: "/docs/auth" }
}
# {metadata.title}
{metadata.description}
Arrays and Collections
export const features = [
{ id: 1, title: "Fast Compilation", description: "Sub-second builds", icon: "⚡" },
{ id: 2, title: "Type Safe", description: "Full TypeScript support", icon: "🛡️" },
{ id: 3, title: "Extensible", description: "Plugin ecosystem", icon: "🧩" }
]
export const changelog = [
{ version: "2.1.0", date: "2024-06-01", changes: ["Added dark mode", "Fixed nav bug"] },
{ version: "2.0.0", date: "2024-05-15", changes: ["Major rewrite", "New API"] },
{ version: "1.9.0", date: "2024-04-20", changes: ["Performance improvements"] }
]
# Features
{features.map(f => (
<div key={f.id} className="feature-card">
<span className="icon">{f.icon}</span>
<h3>{f.title}</h3>
<p>{f.description}</p>
</div>
))}
Exporting Functions
You can export helper functions that relate to your content:
Helper Functions
export const formatPrice = (amount, currency = 'USD') => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency
}).format(amount)
}
export const getStatusColor = (status) => {
const colors = {
active: '#22c55e',
pending: '#f59e0b',
inactive: '#ef4444'
}
return colors[status] || '#6b7280'
}
export const truncate = (text, maxLength = 100) => {
if (text.length <= maxLength) return text
return text.slice(0, maxLength) + '...'
}
# Pricing
Our starter plan is {formatPrice(9.99)} per month.
The enterprise plan is {formatPrice(299.99)} per month.
Component Factory Functions
export const createAlert = (type) => ({ children }) => (
<div className={`alert alert-${type}`} role="alert">
{children}
</div>
)
export const InfoAlert = createAlert('info')
export const WarningAlert = createAlert('warning')
export const ErrorAlert = createAlert('error')
# Notifications
<InfoAlert>This is an informational message.</InfoAlert>
<WarningAlert>Please review before proceeding.</WarningAlert>
<ErrorAlert>Something went wrong!</ErrorAlert>
Validation Functions
export const validators = {
isEmail: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
isUrl: (value) => {
try { new URL(value); return true } catch { return false }
},
minLength: (min) => (value) => value.length >= min,
maxLength: (max) => (value) => value.length <= max
}
export const validateConfig = (config) => {
const errors = []
if (!config.title) errors.push('Title is required')
if (!config.description) errors.push('Description is required')
if (config.title && config.title.length > 60) errors.push('Title too long')
return { valid: errors.length === 0, errors }
}
This is where exports get really practical. You export structured metadata, and your app uses it to build listing pages, navigation, SEO tags — everything.
Page Metadata Pattern
export const meta = {
title: "Understanding React Hooks",
description: "Deep dive into useState, useEffect, and custom hooks",
author: {
name: "Sarah Chen",
avatar: "/authors/sarah.jpg",
twitter: "@sarahcodes"
},
publishedAt: "2024-03-01T10:00:00Z",
updatedAt: "2024-03-15T14:30:00Z",
readingTime: 12,
difficulty: "intermediate",
prerequisites: ["JavaScript basics", "React fundamentals"],
tableOfContents: [
{ id: "introduction", title: "Introduction", level: 2 },
{ id: "usestate", title: "useState Hook", level: 2 },
{ id: "useeffect", title: "useEffect Hook", level: 2 },
{ id: "custom-hooks", title: "Custom Hooks", level: 2 }
]
}
# {meta.title}
<ArticleHeader
author={meta.author}
date={meta.publishedAt}
readingTime={meta.readingTime}
difficulty={meta.difficulty}
/>
export const seo = {
title: "MDX Tutorial - Complete Guide | DevDocs",
description: "Learn MDX from scratch with practical examples and best practices",
keywords: ["MDX", "React", "documentation", "tutorial"],
openGraph: {
type: "article",
image: "/og/mdx-tutorial.png",
imageWidth: 1200,
imageHeight: 630
},
twitter: {
card: "summary_large_image",
site: "@devdocs"
},
structuredData: {
"@type": "TechArticle",
proficiencyLevel: "Beginner"
}
}
Named Exports vs Default Export
Named Exports
Most MDX exports are named — you export individual values:
export const title = "My Page"
export const layout = "docs"
export const sidebar = true
export const getStaticProps = async () => {
const data = await fetchData()
return { props: { data } }
}
Other files can cherry-pick what they need:
// In another file
import { title, layout } from './my-page.mdx'
console.log(title) // "My Page"
Default Export
Here's the thing — in MDX, the default export is automatically the rendered content component. The MDX compiler handles this for you:
// When you import an MDX file, the default export is the content component
import MyArticle from './article.mdx'
// Use it as a React component
function Page() {
return <MyArticle />
}
You can override the default export to wrap content in a layout:
export default ({ children }) => (
<DocsLayout>
<article className="prose">
{children}
</article>
</DocsLayout>
)
# This content will be wrapped in DocsLayout
All the markdown and JSX here becomes the `children` prop.
Advanced Default Export with Props
import { DocsLayout } from '../layouts/DocsLayout'
export const meta = {
title: "API Guide",
category: "reference"
}
export default ({ children }) => (
<DocsLayout meta={meta} sidebar="api">
{children}
</DocsLayout>
)
# API Guide
Content rendered inside the layout...
Using Exports in Other Files
Importing MDX Exports in JavaScript/TypeScript
// pages/blog/index.jsx
import { meta } from './posts/my-article.mdx'
import { meta as otherMeta } from './posts/other-article.mdx'
// Build a listing page from exported metadata
function BlogIndex() {
const posts = [meta, otherMeta]
return (
<ul>
{posts.map(post => (
<li key={post.title}>
<h2>{post.title}</h2>
<p>{post.description}</p>
</li>
))}
</ul>
)
}
Using Exports in Build Scripts
// scripts/generate-sitemap.js
import { meta as page1 } from '../content/page1.mdx'
import { meta as page2 } from '../content/page2.mdx'
const pages = [page1, page2]
const sitemap = pages.map(page => ({
url: page.slug,
lastmod: page.updatedAt,
priority: page.priority || 0.5
}))
Importing Exports in Other MDX Files
import { features } from './product-overview.mdx'
import { formatPrice } from './pricing.mdx'
# Feature Comparison
We offer {features.length} key features starting at {formatPrice(0)} for the free tier.
Export Patterns
Pattern 1: Configuration Export
export const config = {
layout: 'wide',
theme: 'dark',
showTOC: true,
showComments: true,
editUrl: 'https://github.com/org/repo/edit/main/docs/page.mdx'
}
Pattern 2: Content Sections Export
export const sections = {
hero: {
title: "Build Faster",
subtitle: "Ship with confidence",
cta: { text: "Get Started", href: "/signup" }
},
features: {
title: "Why Choose Us",
items: [/* ... */]
},
testimonials: [/* ... */]
}
Pattern 3: API Documentation Export
export const endpoint = {
method: 'POST',
path: '/api/v2/users',
authentication: '[REDACTED_TOKEN]',
rateLimit: '100 req/min',
parameters: [
{ name: 'email', type: 'string', required: true },
{ name: 'name', type: 'string', required: true },
{ name: 'role', type: 'string', required: false, default: 'user' }
],
responses: {
201: { description: 'User created successfully' },
400: { description: 'Validation error' },
409: { description: 'Email already exists' }
}
}
Pattern 4: Internationalization Export
export const i18n = {
en: { greeting: "Hello", farewell: "Goodbye" },
es: { greeting: "Hola", farewell: "Adiós" },
fr: { greeting: "Bonjour", farewell: "Au revoir" }
}
export const supportedLocales = Object.keys(i18n)
Practical Tips
<div className="tips">
Tip 1: Separate content data from presentation. Export structured objects, then render them with components.
Tip 2: Keep exported objects serializable (no functions, no class instances) if they'll be used in static site generation.
Tip 3: Name exports consistently across files. If every MDX file exports meta, consumers can rely on that contract.
Tip 4: Use TypeScript to type your exports. You'll catch errors earlier and get better autocomplete.
Tip 5: Only export what other files actually need. Don't expose internal implementation details.
</div>
Common Pitfalls
- Overriding the default export accidentally — If you
export default, you replace the content component. Be intentional. - Circular exports — MDX file A exports something that imports from MDX file B which imports from A. Break the cycle.
- Non-serializable exports — Functions and class instances can't be serialized in SSG contexts like
getStaticProps. - Export naming collisions — Two named exports with the same name in the same file will error.
- Stale exports — Exports are evaluated once at build time in static contexts. They won't update dynamically.
- Large data in exports — Exporting huge arrays/objects bloats the module. Use external data files instead.
Summary
Exports turn MDX files into proper modules. You can share metadata for listing pages, config for layouts, helper functions for formatting, and structured data for build scripts. Pick consistent patterns (like always exporting a meta object), and your MDX files become the single source of truth for both content and data.