中文 | English
A full-stack modern blog CMS based on Cloudflare Workers
Deeply integrated with D1, R2, KV, Workflows, and other Serverless services.
Demo Site · Deployment Guide · Local Development · Development Guidelines
Note: This project is designed exclusively for the Cloudflare ecosystem and only supports deployment on Cloudflare Workers.
- Post Management — Rich text editor supporting syntax highlighting, image uploads, and draft/publish workflows.
- Version History — Automatic editor snapshots and post version history for safer recovery.
- Tagging System — Flexible post categorization.
- Comment System — Supports nested replies, email notifications, AI-assisted moderation, and richer moderation context.
- Friend Links — User applications, admin moderation, and email notifications.
- Notification System — Supports email and webhook notifications with event-based subscriptions.
- Full-Text Search — High-performance search powered by Orama.
- Media Library — R2 object storage for image management and optimization.
- Authentication — GitHub OAuth login with role-based access control.
- MCP Server — Connect AI clients through OAuth to manage posts, comments, tags, friend links, media, and analytics.
- Analytics — Umami integration for visitor metrics and top posts.
- SEO Enhancements — Canonical URLs, Schema.org structured data, RSS, Sitemap, and Robots support.
- AI Integration — Cloudflare Workers AI integration.
- Theme System — Extensible theme templates, fully supporting replacement of all pages and layouts.
- Import / Export — Supports Markdown import and export, preserving images and frontmatter.
| Service | Purpose |
|---|---|
| Workers | Edge computing and hosting |
| D1 | SQLite database |
| R2 | Object storage (media files) |
| KV | Caching layer |
| Durable Objects | Distributed rate limiting |
| Workflows | Asynchronous tasks (content moderation, scheduled publishing) |
| Queues | Message queues (email notifications) |
| Workers AI | AI capabilities |
| Images | Image optimization |
- Framework: React 19 + TanStack Router/Query
- Styling: TailwindCSS 4
- Forms: React Hook Form + Zod
- Charts: Recharts
- Gateway Layer: Hono (auth routes, media services, cache control)
- Business Layer: TanStack Start (SSR, Server Functions)
- Database: Drizzle ORM + drizzle-zod
- Authentication: Better Auth (GitHub OAuth)
TipTap Rich Text + Shiki Syntax Highlighting
src/
├── features/
│ ├── posts/ # Post management (other modules share similar structure)
│ │ ├── api/ # Server Functions (Public APIs)
│ │ ├── data/ # Data access layer (Drizzle queries)
│ │ ├── posts.service.ts # Business logic
│ │ ├── posts.schema.ts # Zod Schemas + Cache Key Factories
│ │ ├── components/ # Feature-specific components
│ │ ├── queries/ # TanStack Query Hooks
│ │ └── workflows/ # Cloudflare Workflows
│ ├── comments/ # Comments, nested replies, moderation
│ ├── tags/ # Tag management
│ ├── media/ # Media uploads, R2 storage
│ ├── search/ # Orama full-text search
│ ├── auth/ # Authentication, permission control
│ ├── dashboard/ # Admin dashboard statistics
│ ├── email/ # Email notifications (Resend)
│ ├── cache/ # KV caching services
│ ├── config/ # Blog configurations
│ ├── friend-links/# Friend links (applications, moderation)
│ ├── import-export/# Markdown importing/exporting
│ ├── version/ # Version update checker
│ ├── theme/ # Theme system (Contracts, registry, theme implementations)
│ └── ai/ # Workers AI integration
├── routes/
│ ├── _public/ # Public pages (Home, post lists/details, search)
│ ├── _auth/ # Login/Registration related pages
│ ├── _user/ # User specific pages
│ ├── admin/ # Management backend (posts, comments, media, tags, settings)
│ ├── rss[.]xml.ts # RSS Feed
│ ├── sitemap[.]xml.ts # Sitemap
│ └── robots[.]txt.ts # Robots.txt
├── components/ # UI components (ui/, common/, layout/, tiptap-editor/)
├── lib/ # Infrastructure (db/, auth/, hono/, middlewares)
└── hooks/ # Custom React Hooks
All user-facing pages and layouts in Flare Stack Blog are decoupled from business logic via a Theme Contract. You can completely replace the visual presentation layer of the blog without modifying any routing or data logic.
→ Theme Development Guide — Learn how to build your first custom theme from scratch.
Site personalization such as title, description, social links, favicon, and default-theme background assets is now managed from the admin Settings page. src/blog.config.ts mainly serves as seeded defaults and runtime fallback values; see the Theme Development Guide for how themes should consume runtime siteConfig.
| Theme | Preview |
|---|---|
default |
![]() |
fuwari |
![]() |
Contributions are highly welcome! Built a custom theme following the Theme Development Guide? Feel free to submit a PR to list your theme here.
Request → Cloudflare CDN (Edge Cache)
↓ Miss
server.ts (Hono Entry)
├── /api/auth/* → Better Auth
├── /images/* → R2 Media Service
└── Others → TanStack Start
↓
Middleware Injection (db, auth, session)
↓
Route Matching + Loader Execution
↓
KV Cache ←→ Service Layer ←→ D1 Database
↓
SSR Rendering (with cache headers)
Please refer to the Flare Stack Blog Deployment Guide for comprehensive structural steps, addressing Cloudflare resource orchestration, credentials procurement, GitHub OAuth configurations, and detailed visual and written setups for both automated deployment approaches along with troubleshooting.
| File | Purpose |
|---|---|
.env |
Client-side variables (VITE_*), read by Vite |
.dev.vars |
Server-side variables, injected into Worker env by Wrangler |
| Variable | Scope | Description |
|---|---|---|
CLOUDFLARE_API_TOKEN |
CI/CD | Cloudflare API Token (Worker deployment + D1 read/write permissions) |
CLOUDFLARE_ACCOUNT_ID |
CI/CD | Cloudflare Account ID |
D1_DATABASE_ID |
CI/CD | D1 Database ID |
KV_NAMESPACE_ID |
CI/CD | KV Namespace ID |
BUCKET_NAME |
CI/CD | R2 Bucket Name |
BETTER_AUTH_SECRET |
Runtime | Session encryption key. Generate using openssl rand -hex 32 |
BETTER_AUTH_URL |
Runtime | Application URL (e.g., https://blog.example.com) |
ADMIN_EMAIL |
Runtime | Administrator's email address |
GITHUB_CLIENT_ID |
Runtime | GitHub OAuth Client ID |
GITHUB_CLIENT_SECRET |
Runtime | GitHub OAuth Client Secret |
CLOUDFLARE_ZONE_ID |
Runtime | Cloudflare Zone ID |
CLOUDFLARE_PURGE_API_TOKEN |
Runtime | API token with Purge CDN permissions |
DOMAIN |
Runtime | Blog's domain (e.g., blog.example.com) |
| Variable | Scope | Description |
|---|---|---|
THEME |
Build-time | Theme name, defaults to default. Refer to Available Themes. |
TURNSTILE_SECRET_KEY |
Runtime | Cloudflare Turnstile Secret Key for CAPTCHA. |
VITE_TURNSTILE_SITE_KEY |
Build-time | Cloudflare Turnstile Site Key. |
GITHUB_TOKEN |
Runtime | GitHub API Token (for version updates checking to avoid rate limits). |
LOCALE |
Runtime | Default language: zh or en. Default: zh. Used for emails, webhooks, and background task messaging. |
CDN_DOMAIN |
Runtime | Standalone CDN domain (e.g., cdn.example.com), preferentially used during purge. |
PAGEVIEW_SALT |
Runtime | Salt for anonymizing pageview visitor hashes. Generate with openssl rand -hex 16. |
UMAMI_SRC |
Runtime | Umami client-side tracking proxy URL (e.g., https://cloud.umami.is). |
VITE_UMAMI_WEBSITE_ID |
Build-time | Umami Website ID (client-side tracking). |
- Bun >= 1.3
- A Cloudflare account (For remote D1/R2/KV resource simulations)
# Install dependencies
bun install
# Configure environment variables
cp .env.example .env # Client-side variables
cp .dev.vars.example .dev.vars # Server-side variables
# Configure Wrangler
cp wrangler.example.jsonc wrangler.jsonc
# Edit wrangler.jsonc to insert your Cloudflare resource IDs
# Start development server
bun devMethod 1: Email and Password Registration (No third-party service required)
- Visit
http://localhost:3000's registration page and register using theADMIN_EMAILconfigured in.dev.vars. - In the development environment, the verification email won't actually be sent. A link will be printed directly in the terminal console — copy and visit it to complete verification.
- Post-verification involves automatic login, with the system granting admin privileges matched by
ADMIN_EMAIL.
Method 2: GitHub OAuth
- Navigate to GitHub Developer Settings to generate a new OAuth App.
- Homepage URL:
http://localhost:3000, Authorization callback URL:http://localhost:3000/api/auth/callback/github. - Input Client ID and Client Secret configurations into
.dev.vars.
| Command | Definition |
|---|---|
bun dev |
Starts local dev server (default port 3000) |
bun run build |
Builds the production bundle |
bun run test |
Runs the test suites |
bun lint |
Runs the ESLint checker |
bun check |
Initiates Type checking + Lint + Code formatting |
| Command | Definition |
|---|---|
bun db:studio |
Invokes the Drizzle Studio visual database interface |
bun db:generate |
Generates schema migration files |
bun db:migrate |
Safely applies remote D1 migrations and auto-rolls back on failure |
bun db:migrate:local |
Safely applies local D1 migrations and auto-restores local state |
bun db:migrate:unsafe |
Applies remote D1 migrations directly without verification |
bun db:migrate and bun db:migrate:local reuse the schema-defined status constants and verify these counts before and after migration:
posts: total post count and the count for each post statuscomments: total comments, root comments, reply comments, and the count for each comment status
The safety script also adds these safeguards:
- Remote mode: records a D1 Time Travel bookmark by default and automatically restores on verification failure
- Remote mode: if you also want a SQL snapshot for manual incident analysis, run
bun scripts/safe-d1-migrate/main.ts --remote --with-export - Local mode: snapshots
.wrangler/state(or your custom--persist-topath) and restores it automatically on verification failure
The default workspace connects to remote D1/R2/KV resources. If an entirely local ecosystem is needed, simply remove remote: true from wrangler.jsonc entries, allowing Miniflare to simulate these interfaces natively:
Note: Locally simulated data is not synced remotely to Cloudflare, rendering it safe for exploratory setups. For local database migrations, prefer:
bun db:migrate:local
We enthusiastically welcome all code contributions, issues, and feature suggestions! Please examine CONTRIBUTING.en.md to gather deeper contextualization around development patterns.
Prior to modifying fundamental layers, we warmly advise reading Error Handling Quickstart.



{ "d1_databases": [{ "binding": "DB", ... }], // remove "remote": true "r2_buckets": [{ "binding": "R2", ... }], // remove "remote": true "kv_namespaces": [{ "binding": "KV", ... }] // remove "remote": true }