@mdxui/tanstack
v0.2.0
Published
A highly opinionated, MDX-first framework for static pre-rendering, SPA, and SSR — powered by TanStack Start, deployed anywhere or on Cloudflare Workers.
Readme
@mdxui/tanstack
A highly opinionated, MDX-first framework for static pre-rendering, SPA, and SSR — powered by TanStack Start, deployed anywhere or on Cloudflare Workers.
Declare what you need in one config. Get docs, blog, landing pages, app shells, theming, and dark mode — with zero route files and zero imports in MDX.
Quick Start
pnpm add @mdxui/tanstack// vite.config.ts — this is all you need
import { tanstackApp } from '@mdxui/tanstack'
export default tanstackApp({
config: {
site: { name: 'My App' },
docs: true,
blog: true,
landing: true,
}
})vite dev # Development
vite build # Production buildNo src/routes/ needed — routes are generated automatically.
What You Get
| Config Key | What It Does |
|------------|-------------|
| docs: true | Fumadocs site from content/docs/ with prerendering |
| blog: true | Blog from content/blog/ with tags, reading time, related posts |
| landing: true | Landing pages from content/landing/ with full component registry |
| app: '/app' | SPA shell at /app/* for authenticated features |
| admin: '/admin' | Admin panel shell (same as app) |
| cloudflare: {} | Cloudflare Workers deployment with static assets + SSR |
Batteries included. One install gives you TanStack Start, MDX compilation, Tailwind CSS, fumadocs, and 200+ UI components. The only peer dependencies are react, react-dom, and vite.
Directory Structure
project/
├── vite.config.ts # tanstackApp() — the only config file
├── wrangler.jsonc # Optional — for Cloudflare deployment
├── content/
│ ├── docs/ # MDX documentation pages
│ │ ├── index.mdx
│ │ └── getting-started.mdx
│ ├── blog/ # MDX blog posts
│ │ ├── index.mdx # Optional blog page config
│ │ └── hello-world.mdx
│ └── landing/ # MDX landing pages
│ ├── index.mdx # Home page (/)
│ ├── pricing.mdx # /pricing
│ └── terms.mdx # /terms
├── app/routes/ # Custom app routes (SPA)
└── .tanstack/ # Generated (gitignored)
└── routes/ # Auto-generated route filesConfiguration
All fields are optional. Defaults work out of the box.
import { tanstackApp } from '@mdxui/tanstack'
export default tanstackApp({
config: {
// Site metadata
site: {
name: 'OAuth.do',
description: 'OAuth as a Service',
logo: '/logo.svg',
theme: 'stripe', // Any @mdxui/themes preset
mode: 'system', // 'light' | 'dark' | 'system'
layout: {
navbar: {
component: 'Navbar17', // or 'Navbar5'
menu: [
{ name: 'Docs', link: '/docs' },
{ name: 'Blog', link: '/blog' },
],
githubUrl: 'https://github.com/...',
primaryCta: { text: 'Get Started', url: '/app' },
},
footer: {
component: 'FooterSmall', // or 'Footer7', 'FooterLarge'
domain: 'oauth.do',
legalLinks: [
{ name: 'Terms', href: '/terms' },
{ name: 'Privacy', href: '/privacy' },
],
},
background: {
noise: true,
grid: false,
glow: false,
},
},
},
// Content types (boolean for defaults, or object for customization)
docs: true,
blog: true,
landing: true,
// SPA shells
app: '/app',
// Deployment
cloudflare: {},
},
// Vite config overrides
vite: {
server: { port: 4000 },
},
})Separate Config File
If you prefer, you can use a separate tanstack.config.ts:
// tanstack.config.ts
import { defineConfig } from '@mdxui/tanstack'
export default defineConfig({
site: { name: 'My App' },
docs: true,
blog: true,
landing: true,
})// vite.config.ts
import { tanstackApp } from '@mdxui/tanstack'
export default tanstackApp()Content Authoring
Blog Posts
MDX files in content/blog/. Components are auto-registered — no imports needed.
---
title: Getting Started with TanStack
description: Learn how to build modern web apps
date: 2024-01-15
author:
name: John Doe
image: /authors/john.jpg
tags: [tutorial, tanstack]
image: /images/blog/intro.jpg
featured: true
---
# Getting Started
<Callout type="tip">
Components work without imports!
</Callout>
Write your content here. Code blocks get copy buttons automatically.Available frontmatter: title, description, date, author, tags, image, featured, draft, series, seo, and more. See the blog schema for the full list.
Landing Pages
MDX files in content/landing/. index.mdx becomes the homepage.
---
title: "Welcome to My App"
---
<Hero title="Build faster" description="Ship with confidence" />
<Features features={[
{ title: 'Fast', description: 'Lightning fast builds' },
{ title: 'Secure', description: 'Bank-grade security' },
]} />
<Pricing tiers={[...]} />
<FAQ items={[...]} />
<CTA title="Ready to start?" />All @mdxui/neo components (Hero, Features, Pricing, CTA, FAQ, Stats, Logos, Testimonials) are available without imports.
Frontmatter Overrides
Control layout per-page:
---
title: Terms of Service
template: legal # Wraps in prose styling
showBackground: false # Disables background effects
---Cloudflare Workers
Add cloudflare: {} to your config and create a wrangler.jsonc:
// wrangler.jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-app",
"compatibility_date": "2026-02-12",
"compatibility_flags": ["nodejs_compat"],
"main": "@mdxui/tanstack/server",
"observability": { "enabled": true }
}No worker entry file needed — the built-in server handler takes care of everything.
Custom Worker Entry (Optional)
If you need middleware, scheduled handlers, queues, or Durable Objects:
// worker.ts
import handler from '@mdxui/tanstack/server'
export default {
fetch: handler.fetch,
async scheduled(event, env, ctx) {
// Cron handler
},
}Then point "main" in wrangler.jsonc to "./worker.ts".
For middleware convenience, createTanstackHandler wraps the handler with an onRequest hook:
import { createTanstackHandler } from '@mdxui/tanstack/server'
export default createTanstackHandler({
onRequest: (request, env, ctx) => {
if (new URL(request.url).pathname === '/api/health') {
return new Response(JSON.stringify({ ok: true }))
}
},
})Virtual Modules
Available for advanced use cases:
import { posts, getPost, getPosts, getAllTags } from 'virtual:mdx-blog/posts'
import { items, getItem } from 'virtual:mdx-content/landing'
import { theme, mode } from 'virtual:@mdxui/tanstack/theme-config'
import { layoutConfig } from 'virtual:@mdxui/tanstack/layout-config'Custom Content Types
Add arbitrary MDX content sources beyond docs/blog/landing:
export default tanstackApp({
config: {
content: {
tutorials: { dir: 'content/tutorials', basePath: '/tutorials' },
changelog: { dir: 'content/changelog', basePath: '/changelog' },
},
},
})Access via virtual modules:
import { items, getItem } from 'virtual:mdx-content/tutorials'Package Exports
| Import | Purpose |
|--------|---------|
| @mdxui/tanstack | Core APIs (defineConfig, tanstackApp, createPages) |
| @mdxui/tanstack/server | Worker handler and createTanstackHandler |
| @mdxui/tanstack/mdx | MDX component registry (MDXProvider, registries) |
| @mdxui/tanstack/components | UI components (LandingLayout, ProseWrapper) |
| @mdxui/tanstack/client | Type declarations for virtual modules |
| @mdxui/tanstack/config | Config utilities (defineConfig) |
| @mdxui/tanstack/routes | Route helpers (createRootHead) |
| @mdxui/tanstack/plugin | Vite plugin (tanstack()) for custom setups |
| @mdxui/tanstack/vite | Virtual module plugin factories |
Peer Dependencies
The only packages you need in your project:
{
"react": ">=19.0.0",
"react-dom": ">=19.0.0",
"vite": ">=6.0.0"
}Everything else — TanStack Start, MDX, Tailwind, fumadocs, Cloudflare, and 200+ UI components — is included.
License
MIT
