Personal authority blog. Astro + MDX + Tailwind. Designed to compound SEO, be cited by LLMs, and serve as the canonical source for everything cross-posted to LinkedIn, X, and Hacker News.
| Layer | Choice |
|---|---|
| Framework | Astro 5 (zero-JS by default) |
| Content | MDX via Astro Content Collections |
| Styling | Tailwind via @astrojs/tailwind |
| RSS | @astrojs/rss |
| Sitemap | @astrojs/sitemap |
| Hosting | Cloudflare Pages |
| Analytics | Cloudflare Web Analytics (drop snippet in Base.astro) |
No React, no client libraries beyond a single ~3KB tweaks-panel script.
cd astro
npm install
npm run dev # http://localhost:4321
npm run build # static output → dist/
npm run preview
astro/
├── astro.config.mjs — site URL, integrations
├── tailwind.config.mjs — design tokens as CSS vars
├── public/
│ ├── tweaks.js — accent/density/theme panel (vanilla)
│ ├── favicon.svg
│ └── robots.txt
└── src/
├── styles/global.css — full design system
├── layouts/Base.astro — <head>, JSON-LD, top bar, footer
├── components/
│ ├── TopBar.astro
│ ├── Footer.astro
│ ├── PostRow.astro — used by Home + Archive
│ └── BarChart.astro — inline SVG chart (MDX-usable)
├── content/
│ ├── config.ts — Zod schema for posts
│ └── posts/*.mdx — one essay per file
└── pages/
├── index.astro
├── archive.astro
├── about.astro
├── posts/[...slug].astro
└── rss.xml.ts
Drop a file at src/content/posts/<slug>.mdx:
---
title: "Latency budgets for LLM apps"
description: "A back-of-the-envelope model for 'how slow is too slow' that survived a year in prod."
pubDate: 2026-06-01
tag: "Engineering"
---
Your essay starts here. Use any MDX component:
import BarChart from "~/components/BarChart.astro";
<BarChart
months={["Jan","Feb","Mar"]}
series={[
{ label: "p50", color: "rule", values: [40,42,45] },
{ label: "p95", color: "accent", values: [80,72,68] },
]}
caption="Latency over Q1"
/>
tag is constrained by the Zod schema in content/config.ts — add new
ones there. Reading time and word count are computed at build.
The single-post template builds the TOC from h2s. The design uses a
section-number prefix like ## /01 Why most teams give up. The prefix
is auto-stripped from the TOC label but kept in the rendered heading.
Use {#custom-slug} if you want a stable anchor for citations.
The base layout emits, per page:
<link rel="canonical"> (auto)og: + twitter: cardsJSON-LD block via the jsonLd prop/sitemap-index.xml) via integration/rss.xml)Single posts emit a BlogPosting schema with headline, author,
datePublished, wordCount, and mainEntityOfPage — the fields
LLM crawlers actually use.
astro/ directory to a GitHub repo (or use it as the repo root).npm run build. Output: dist. Root: astro/ (if nested).vedangkarwa.com as a custom domain. Cloudflare handles TLS + DNS.