Why This Stack?
When building a blog in 2026, you have many choices. Here's why I chose this combination:
| Aspect | Choice | Reason |
|---|---|---|
| Framework | Next.js 16 | SSG, RSC, great DX |
| Content | Velite | Type-safe, actively maintained |
| Styling | Tailwind v4 | CSS-first, modern |
| UI | shadcn/ui | Accessible, customizable |
Setting Up Velite
Velite is a content management system that works at build time:
bun add veliteCreate a velite.config.ts:
import { defineConfig, s } from "velite";
export default defineConfig({
collections: {
posts: {
name: "Post",
pattern: "content/posts/**/*.md",
schema: s.object({
title: s.string(),
date: s.isodate(),
categories: s.array(s.string()).optional(),
tags: s.array(s.string()).optional(),
summary: s.string().optional(),
slug: s.string().optional(),
}),
},
},
});Data Flow
content/posts/*.md
│
▼
Velite (build time)
│
├──→ .velite/data/posts.json
├──→ .velite/index.d.ts
│
▼
Next.js SSG → Static HTML
Key Benefits
- Type Safety: Velite generates TypeScript types from your schema
- Zero Runtime: Everything is resolved at build time
- Hot Reload: Velite watches for file changes in development
- No Database: File system is the single source of truth