A personal site + blog template for developers who'd rather write posts than build infrastructure.
TanStack Start · React 19 · Tailwind CSS v4 · shadcn/ui · MDX · RSS · Cloudflare Workers
Demo: template.karngyan.com · Author's site built on the same stack: karngyan.com
- ⚡ TanStack Start — file-based routing, SSR, typed loaders, server routes
- 🎨 Tailwind CSS v4 + shadcn/ui — CSS-first tokens (oklch), dark/light/system theme with no flash (press
dto toggle) - ✍️ MDX articles — folders in
src/content/articles/, Shiki syntax highlighting, GFM tables, inline React components - 📡 RSS, sitemap, robots.txt, llms.txt — server routes generated from your content and config
- 🖼️ Open Graph images — generated at build time with satori (default + per-article)
- ☁️ Cloudflare Workers — default deploy target, one command or auto-deploy via GitHub Actions
- 📌 mise.toml — exact node/pnpm pins, zero "works on my machine"
- 🤖 Claude-friendly —
CLAUDE.mdteaches coding agents the repo's architecture and recipes
- Click Use this template on GitHub (or
pnpm dlx degit karngyan/karngyan.com my-site) - Install the toolchain and dependencies:
mise install # installs the pinned node + pnpm (https://mise.jdx.dev)
pnpm install
pnpm dev # → http://localhost:3000Everything personal lives in three places:
site.config.ts— name, canonical URL, title/description, email, socials, nav, resume toggle, work history, optional Plausible analytics. Fully typed; a typo fails the build.- Images —
src/assets/avatar.png(header),src/assets/portrait.jpg(about),src/assets/photos/(home photo strip),public/logos/(work history),public/favicon*. - Content — articles in
src/content/articles/<slug>/page.mdx; page prose in the route files marked with✏️(src/routes/index.tsx,about/,uses/,projects/).
Write an article:
mkdir src/content/articles/my-first-post
$EDITOR src/content/articles/my-first-post/page.mdximport { ArticleLayout } from '../../../components/article-layout'
export const article = {
title: 'My first post',
description: 'Short summary that shows up in lists, RSS, and OG cards.',
date: '2026-07-09',
author: 'you',
}
export const metadata = {
title: article.title,
description: article.description,
}
export default (props) => <ArticleLayout article={article} {...props} />
Hello! **Markdown** and <em>JSX</em> both work here.The article index, RSS feed, sitemap, and OG images all regenerate on the next build.
One-time setup:
pnpm wrangler loginThen, every deploy:
pnpm run deploy # = pnpm build && wrangler deployYour site is live on <name>.<account>.workers.dev. Add a custom domain in the Cloudflare dashboard (Workers → your worker → Settings → Domains & Routes), then set url in site.config.ts to match.
Pushes to the default branch deploy automatically via .github/workflows/deploy.yml. Add two repository secrets:
CLOUDFLARE_API_TOKEN— create at dash.cloudflare.com → My Profile → API Tokens ("Edit Cloudflare Workers" template)CLOUDFLARE_ACCOUNT_ID— on the right sidebar of your account's Workers overview page
The build uses nitro, so other presets (Node server, Netlify, Vercel, …) work by changing the preset in vite.config.ts — see the nitro deploy docs.
| Command | What it does |
|---|---|
pnpm dev |
Dev server on :3000 |
pnpm build |
OG images + production build → .output/ |
pnpm test |
vitest |
pnpm check |
prettier + eslint (auto-fix) |
pnpm run deploy |
build + wrangler deploy |
PRs welcome — see CONTRIBUTING.md.
Distributed under the MIT License. See LICENSE for more information.
Karn - @gyankarn - mail@karngyan.com

