Woltex

Start a Fumadocs Blog in 10 Minutes

Building in public? Sometimes you need more than X posts to document your journey; or to create comprehensive product documentation for your users. Here's how to set up a beautiful, fast documentation or blogging site with Fumadocs.

Why Fumadocs?

Most documentation frameworks either look dated or are overkill for indie builders. Fumadocs is lightweight yet powerful enough for serious projects.

BenefitWhy It Matters
Built on React/Next.jsUse the tools you already know, full control over customization
MDX SupportWrite in Markdown, embed React components when needed
Beautiful by DefaultProfessional UI out of the box - no design skills required
Fast PerformanceStatic generation + incremental builds = instant page loads
Rich ComponentsSteps, tabs, callouts, accordions, cards - all built-in and ready to use
SEO OptimizedMetadata, sitemap, Open Graph - everything you need for discoverability

Perfect for Building in Public

Fumadocs is designed for technical content. Code blocks, API references, step-by-step guides - it handles them all beautifully.


Quick Start

Get your Fumadocs blog running in 10 minutes:

Create your project

Create with pnpm
pnpm create fumadocs-app
Create with npm
npx create-fumadocs-app@latest
Create with yarn
yarn create fumadocs-app

The CLI will ask you a few questions:

Project name

  • Enter your project name (e.g., my-docs, my-blog)

Choose a template

  • Next.js: Fumadocs MDX (with RSC)
  • Waku: Fumadocs MDX
  • React Router: Fumadocs MDX (not RSC)
  • React Router SPA: Fumadocs MDX (not RSC)
  • Tanstack Start: Fumadocs MDX (not RSC)
  • Tanstack Start SPA: Fumadocs MDX (not RSC)

I am using Tanstack Start with Server Side Rendering on Cloudflare Workers. But you can use any other framework you like.

Use /src directory? (on Next.js)

  • Yes - Use /src directory
  • No - Use /app directory

Configure linter?

  • Disabled - Start simple
  • ESLint or Biome - Add later if needed

Choose a search solution?

  • Default (local search powered by Orama, recommended) - Works offline, no external dependencies
  • Orama Cloud - Cloud-based search with better performance for large sites

Install packages automatically?

  • Yes - Installs dependencies for you
  • No - You'll need to run pnpm install manually

Project structure

After creation, you'll have this structure:

my-docs/
├── content/
│   └── docs/             # Your content here
│       ├── index.mdx     # Landing page
│       └── meta.json     # Navigation structure
├── src/                   # Application routes (Next.js)
│   ├── layout.tsx         # Root layout
│   ├── page.tsx          # Homepage
│   └── [[...slug]]/      # Dynamic doc routes
├── public/               # Static assets
└── package.json

Start the dev server

cd my-docs
pnpm install  # if you didn't auto-install
pnpm dev

Your site is now running at http://localhost:3000! 🎉

Write your first post

Create a new file in content/blog/ (or content/docs/ for documentation):

content/blog/my-first-post.mdx
---
title: "My First Post"
description: "Starting my build in public journey"
author: "Your Name"
date: 2025-12-29
tags: ["Getting Started", "Build in Public"]
---

# My First Post

This is my first post using Fumadocs. Here's what I'm building...

## What I'm Working On

- Feature 1
- Feature 2
- Feature 3

```typescript
// Example code block with syntax highlighting
function hello() {
  console.log("Hello, world!");
}
```

Add it to `content/blog/meta.json`:

```json title="content/blog/meta.json"
{
  "title": "Blog",
  "pages": [
    "index",
    "my-first-post"
  ]
}

Using Fumadocs Components

The real power of Fumadocs comes from its built-in components. Here's what you can use:

Steps component

Perfect for tutorials and guides:

<Steps>

<Step>### First step Content for step 1</Step>

<Step>### Second step Content for step 2</Step>

</Steps>

Tabs component

Show alternative approaches:

<Tabs items={['Option 1', 'Option 2']}>
<Tab value="Option 1">
Content for first option
</Tab>

<Tab value="Option 2">
Content for second option
</Tab>
</Tabs>

Callouts

Highlight important information:

<Callout type="info">Useful information for readers</Callout>

<Callout type="warn">Warning - be careful here!</Callout>

<Callout type="tip">Pro tip for better results</Callout>

Accordions

Collapsible content for FAQs:

<Accordions>
<Accordion title="How do I do X?">
Answer to the question
</Accordion>

<Accordion title="What about Y?">
Another answer
</Accordion>
</Accordions>

Cards

Beautiful link cards:

<Cards>
  <Card title="Documentation" description="Read the full docs" href="/docs" />
  <Card
    title="GitHub"
    description="View the source code"
    href="https://github.com/..."
  />
</Cards>

Import Required

Remember to import components at the top of your MDX file: tsx import{" "} {(Step, Steps)} from 'fumadocs-ui/components/steps'; import {Callout} from 'fumadocs-ui/components/callout';


Deployment

Ready to ship? Use your preferred deployment platform. The tech stack for this blog is Tanstack Start + Cloudflare Workers to benefit from SSR and edge locations.

1. Configure Vite

Add the Cloudflare adapter to your vite.config.ts:

apps/blog/vite.config.ts
import { cloudflare } from "@cloudflare/vite-plugin";
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [
    // ... other plugins
    tanstackStart(),
    cloudflare({ viteEnvironment: { name: "ssr" } }),
  ],
});

2. Configure Wrangler

Create a wrangler.jsonc file for Cloudflare Workers configuration. Note the usage of nodejs_compat and the assets directory:

apps/blog/wrangler.jsonc
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "woltexai-blog",
  "compatibility_date": "2025-12-01",
  "compatibility_flags": ["nodejs_compat"],
  "main": "@tanstack/react-start/server-entry",
  "assets": {
    "directory": "./dist/client",
    "binding": "ASSETS"
  }
}

3. Setup CI/CD

Use GitHub Actions to deploy automatically. Here is the relevant part of the workflow:

.github/workflows/deployment.yml
- name: Deploy blog to Cloudflare Workers (production)
  if: github.ref == 'refs/heads/main'
  uses: cloudflare/wrangler-action@v3
  with:
    apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
    accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
    workingDirectory: apps/blog
    command: deploy

Now, every push to main will deploy the docs/blog to the edge! 🚀


Customization Tips

Add your branding

Edit app/layout.tsx to customize the site:

app/layout.tsx
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <DocsLayout
          nav={{
            title: "Your Blog Name",
            // Add your logo
          }}
          links={[
            { text: "Home", url: "/" },
            { text: "Blog", url: "/blog" },
          ]}
        >
          {children}
        </DocsLayout>
      </body>
    </html>
  );
}

Add analytics

Track your blog visitors with Rybbit (privacy-friendly, lightweight analytics):

For Tanstack Start / React Router:

src/routes/__root.tsx
export const Route = createRootRoute({
  head: () => ({
    scripts: [
      {
        src: import.meta.env.VITE_RYBBIT_TRACKING_URL,
        defer: true,
        "data-site-id": import.meta.env.VITE_RYBBIT_SITE_ID,
      },
    ],
  }),
  component: RootComponent,
});

For Next.js:

app/layout.tsx
import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Script
          src={process.env.NEXT_PUBLIC_RYBBIT_TRACKING_URL}
          data-site-id={process.env.NEXT_PUBLIC_RYBBIT_SITE_ID}
          defer
        />
      </body>
    </html>
  );
}

Other Analytics Options

Rybbit is what Woltex uses, but Plausible, Fathom, and Umami are also great privacy-friendly alternatives.


Next Steps


On this page