Skip to content

vstorm-co/astro-blog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

10 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

astro-blog πŸ“

The blog template that ships with a browser-based admin panel β€” write and publish MDX posts without touching a text editor.
Built on Astro 6 + Tailwind CSS 4, zero JS on reading pages, 100 Lighthouse across all four categories.

CI Made with Astro Node β‰₯ 20 Bun β‰₯ 1 License: MIT Security Policy X

Live Demo

Dark mode Light mode

astro-blog β€” admin panel


πŸš€ Quick Start

bunx degit vstorm-co/astro-blog my-blog && cd my-blog && bun install && bun run dev

Open http://localhost:4321/admin/ β€” your blog editor is ready.

npm users: npx degit vstorm-co/astro-blog my-blog && cd my-blog && npm install && npm run dev


✨ Features

  • πŸ›  Built-in admin panel β€” browser-based MDX editor with live preview, autosave, drag-and-drop images, and a component palette. Stripped from every production build.
  • ⚑ Zero JS on reading pages β€” no framework runtime, no hydration cost. Home page ships 0 KB of JavaScript.
  • πŸ“ MDX-first with 22 ready-made blog components: Callout, Figure, Stat, Timeline, Terminal, FileTree, Diff, Gallery, Tweet, Bookmark, and more
  • 🎨 Single-file config β€” title, author, nav, socials, accent colour, feature flags all in src/site.config.ts
  • πŸŒ— Dark + light mode with pre-paint init (zero FOUC) and prefers-color-scheme fallback
  • ✍️ Scheduled posts β€” set a future pubDate, post goes live on the next build after that time
  • 🏷️ Tag pages auto-generated from frontmatter
  • πŸ“‘ RSS feed, sitemap, robots.txt built at compile time
  • πŸš€ One-click deploy to Vercel, Netlify, or Cloudflare Pages
  • πŸ”· TypeScript + Zod schemas β€” typed frontmatter, zero runtime surprises
  • πŸ”’ ESLint + Prettier + Husky β€” enforced code style from the first commit

βœ… Lighthouse Score

astro-blog Lighthouse score β€” 100 Performance, 100 Accessibility, 100 Best Practices, 100 SEO


πŸ†š Why astro-blog?

astro-blog AstroPaper Fuwari Raw Astro
Admin panel (browser editor) βœ… ❌ ❌ ❌
Zero JS on reading pages βœ… ❌ ❌ βœ…
100 Lighthouse (all 4) βœ… βœ… β€” β€”
22 MDX components βœ… ❌ ❌ ❌
Drag-and-drop image upload βœ… ❌ ❌ ❌
Scheduled posts βœ… ❌ ❌ ❌
Single-file config βœ… βœ… βœ… ❌
Dark + light mode βœ… βœ… βœ… β€”
One-click deploy βœ… βœ… βœ… β€”

The admin panel is the differentiator β€” no other Astro blog template ships one.


πŸ›  First 10 Minutes

After cloning, open src/site.config.ts and work through this list:

  1. Set your identity β€” website, title, author, description, accent
  2. Update socials β€” edit src/socials.ts, keep only the providers you use
  3. Rewrite the About page β€” src/data/pages/about.mdx or use the admin panel
  4. Delete example posts β€” remove everything in src/data/blog/ and write your own
  5. Replace the favicon β€” drop your SVG at public/favicon.svg
  6. Set an OG image β€” 1200Γ—630 PNG at public/og-default.png (or run python3 scripts/generate-og.py)
  7. Deploy β€” push to GitHub and click one of the deploy buttons below
  8. Protect main β€” on GitHub: require PR + CI green before merge
  9. Turn on Discussions β€” for open-ended questions from readers
  10. Fill .github/FUNDING.yml β€” if you accept sponsorship

πŸ–ŠοΈ Writing Posts

Option A β€” Admin panel (recommended)

Start the dev server and open localhost:4321/admin/:

  • Split-pane MDX editor with autosave (2 s debounce, Cmd+S forces save)
  • Component palette β€” click Insert, snippet + import land at your cursor
  • Image drag-and-drop β€” files written to public/images/blog/<slug>/
  • Live preview inside an iframe of the real post layout
  • Rename slug / delete post from the sidebar

The admin panel is dev-only β€” production builds 404 the route.

Option B β€” CLI

bun run new-post "My post title"
# β†’ src/data/blog/my-post-title.mdx  (draft: true by default)

Frontmatter reference

---
title: "My post title"
description: "One-line summary β€” used in meta tags and post cards."
pubDate: 2026-05-01
updatedDate: 2026-05-15 # optional
author: "Jane Doe"
tags: ["astro", "mdx"]
draft: false # excluded from prod builds when true
featured: false # pinned to the home page featured strip
cover: "./cover.jpg" # optional, relative to the MDX file
ogImage: "/custom-og.png" # optional per-post OG override
canonicalURL: "https://…" # optional, for cross-posts
---

Scheduling a post

Set pubDate to a future date. The post is invisible until the next build after that time. For automatic builds:

  1. Add a DEPLOY_HOOK_URL repo secret (Vercel / Netlify / CF each provide one).
  2. Set repo variable SCHEDULED_REBUILD=1.
  3. .github/workflows/scheduled-rebuild.yml hits the hook hourly.

🧩 MDX Components

22 components grouped by purpose:

Group Components
Prose Callout InfoCard PullQuote Aside
Data Stat TwoColumn Comparison Timeline
Media Figure Gallery VideoEmbed Tweet Bookmark
Technical CodeGroup Terminal FileTree Diff Kbd Details
Structure Steps Badge Divider

All components live in src/components/blog/. See them in action in src/data/blog/mdx-component-reference.mdx.

Adding your own component

Drop an .astro file in src/components/blog/ with three annotation comments:

{/* @mdx-label MyComponent */}
{/* @mdx-description One-line description shown in the palette. */}
{
  /* @mdx-snippet
<MyComponent prop="example">
  Body text
</MyComponent>
*/
}

The admin palette picks it up on the next refresh β€” no other code changes needed.


βš™οΈ Configuration

File What you change
src/site.config.ts Title, author, nav, socials, accent colour, feature flags
src/socials.ts Social links and share targets
src/styles/global.css Design tokens β€” colours, fonts, radii, shadows
src/styles/prose.css Post body typography
src/data/blog/ Blog posts
src/data/pages/ About / Uses / Now / etc.
public/favicon.svg Favicon
public/og-default.png Default OG image (1200 Γ— 630 px)

Feature flags

features: {
  search: false,           // Pagefind-powered /search/ page (requires build step)
  archive: true,           // /archive/ β€” chronological post list
  dynamicOg: false,        // per-post OG via Satori
  editPost: false,         // "Edit on GitHub" link on each post
  adminPanel: true,        // dev-only admin UI
  lightAndDarkMode: true,  // theme toggle visible / hidden
}

⚑ Commands

Command Action
bun run dev Start dev server at localhost:4321
bun run build Type-check + build to ./dist/
bun run preview Preview the production build locally
bun run new-post "Title" Scaffold a new draft post
bun run optimize-images Resize + convert blog images to WebP
bun run lint Run ESLint
bun run format Format with Prettier
bun run test Run Vitest unit tests

πŸ—‚ Project Structure

src/
β”œβ”€ site.config.ts       # ← start here: identity, nav, features
β”œβ”€ socials.ts
β”œβ”€ content.config.ts    # Zod schemas
β”œβ”€ data/
β”‚  β”œβ”€ blog/             # MDX posts
β”‚  └─ pages/            # About, Uses, etc.
β”œβ”€ layouts/             # Base / Post / Page
β”œβ”€ components/
β”‚  β”œβ”€ blog/             # 22 MDX components
β”‚  β”œβ”€ layout/           # Header / Footer / SEO
β”‚  β”œβ”€ home/             # Hero / LatestPosts / FeaturedStrip
β”‚  β”œβ”€ post/             # PostCard / TOC / Pagination / ShareLinks
β”‚  β”œβ”€ islands/          # React islands (CopyCode, Search, TOC scrollspy)
β”‚  └─ admin/            # dev-only admin panel
β”œβ”€ lib/
β”‚  β”œβ”€ posts.ts          # content helpers
β”‚  β”œβ”€ schemas.ts        # JSON-LD builders
β”‚  └─ slug.ts
β”œβ”€ pages/               # file-based routes
└─ styles/              # global.css, prose.css

public/
β”œβ”€ favicon.svg
β”œβ”€ og-default.png
β”œβ”€ _headers / _redirects   # Cloudflare Pages headers
└─ images/blog/<slug>/     # per-post images (managed by admin)

scripts/
β”œβ”€ new-post.ts             # post scaffolder
β”œβ”€ optimize-images.py      # WebP optimiser
└─ generate-og.py          # OG image generator

🚒 Deploy

Platform One-click
Vercel Deploy with Vercel
Netlify Deploy to Netlify
Cloudflare Pages Deploy to Cloudflare

Security headers and /admin/* blockers are pre-configured for all three in vercel.json, netlify.toml, and public/_headers.


πŸ›  Tech Stack

Framework Astro 6
Content MDX + Astro Content Collections
Styling Tailwind CSS 4 + CSS custom properties
Syntax highlighting Shiki via Expressive Code
Editor (admin) CodeMirror 6
Type checking TypeScript strict mode
Testing Vitest
Linting / formatting ESLint + Prettier
Git hooks Husky + lint-staged

❓ FAQ

Why Astro, not Next.js? Content-first. Zero JS by default, typed frontmatter via content collections, no runtime framework lock-in.

Can I use pure Markdown instead of MDX? Yes β€” rename .mdx β†’ .md. The content loader accepts both. MDX components only work in .mdx files.

How do I add comments? We don't ship a comment system. Giscus takes ~10 lines at the bottom of src/layouts/PostLayout.astro.

Is the admin panel safe to expose publicly? No. It has no authentication and writes to your filesystem. It binds to 127.0.0.1 in dev and production builds 404 the route.

Will there be i18n? Not in this template. Use Astro's i18n recipe directly.


⭐ Star History

Star History


🀝 Contributing

See CONTRIBUTING.md for coding conventions, commit style, and how to run the test suite. Issues and PRs welcome.

Please read CODE_OF_CONDUCT.md before participating. Report security vulnerabilities via SECURITY.md.

πŸ“„ License

MIT Β© Vstorm


Need a custom blog or content platform?

We're Vstorm β€” an Applied Agentic AI Engineering Consultancy.
astro-blog is the template we use for our own writing. We build production-grade web apps too.

Talk to us



Built on Astro Β· Tailwind CSS Β· MDX Β· Shiki Β· CodeMirror