Template for a TanStack Start + Cloudflare Workers blog.
- Live demo: https://template.mafifi.dev
- Source post: https://mafifi.dev/posts/accidentally-built-a-blog-platform/
git clone git@github.com:mohamede1945/tanstack-start-blog.git
cd tanstack-start-blog
npm installStart the dev server:
npm run devUpdate the core brand + content:
src/consts.ts: site title, description, canonical URLpublic/robots.txt: sitemap URLvite.config.ts:sitemap.hostwrangler.json: Cloudflare Worker namesrc/components/logo.tsx: site name in the headersrc/components/bio.tsx: author bio under each postsrc/components/footer.tsx: social links + copyrightsrc/data/pages/about.mdx: about page contentsrc/data/posts/*: replace the template posts with your ownpublic/assets/*: swap images used across the site
After you update the brand assets, regenerate OG images:
Ensure to bump
manifestVersioninscripts/generate-all-post-og.ts
npm run og:socialnpm run og:all-posts
Optional: hide the newsletter form:
VITE_NEWSLETTER_ENABLED=false
- File-based routes via TanStack Router
- Shadcn components + Tailwind v4
- Prose UI for rich content rendering
- Content collections for Markdown + frontmatter + mdast
- safe-mdx renderer for MDX (Cloudflare Workers compatible)
- RSS generated by
scripts/generate-rss.ts - Cloudflare Workers SSR
- Newsletter signup via Loops (footer form + server function)
- Remotion OG images (custom layouts in
src/remotion/)
src/routes/: app routessrc/components/: shared UIsrc/components/mdx.tsx: safe-mdx rendering for MDX contentsrc/data/posts/: Markdown postssrc/data/pages/: Markdown/MDX pages (not blog posts)public/: static assetsscripts/generate-rss.ts: RSS generatorsrc/remotion/: Remotion compositions for OG imagesscripts/generate-post-og.ts: post OG generator (reads MD/MDX frontmatter title)scripts/generate-all-post-og.ts: incremental post OG generator (manifest inog-metadata.json)
| Command | Action |
|---|---|
npm install |
Install dependencies |
npm run dev |
Start dev server at localhost:5173 |
npm run build |
Build production assets |
npm run preview |
Preview the build |
npm run deploy |
Deploy to Cloudflare |
npm run typecheck |
Typecheck |
npm run lint |
Biome + Oxlint |
npm run lint:deep |
Lint + type-aware oxlint + eslint |
npm run lint:fix |
Fix with Biome + Oxlint |
npm run lint:changed |
Biome on changed files |
npm run lint:staged |
Biome on staged files |
npm run clean |
tsgo project clean |
npm run og:social |
Render public/assets/social.webp via Remotion |
npm run og:post -- <path> |
Render post OG from MD/MDX title into public/assets/og/<slug>.webp |
npm run og:all-posts |
Render all post OG images incrementally into public/assets/og/ (manifest: og-metadata.json) |
og-metadata.json |
Bump manifestVersion in scripts/generate-all-post-og.ts when Remotion template changes |
Required env vars:
Create a .env file.
LOOPS_API_KEYLOOPS_MAILING_LIST_NEWSLETTER
To hide the newsletter form without removing code, set:
VITE_NEWSLETTER_ENABLED=false
To remove it entirely, delete the footer section in src/components/footer.tsx and remove the
newsletter components and server action.
Customize src/remotion/post-og-image.tsx and src/remotion/social-image.tsx, then regenerate the
images with the og:* scripts above.