Building a Personal Site with Astro
A walkthrough of how this site was built — Astro, Tailwind CSS, content collections, and a zen minimalist design language.
Why Astro?
When I set out to rebuild my personal site, I had a few non-negotiable requirements:
- Static output — no server needed, deploy anywhere
- Markdown blog — write posts in
.mdfiles, not a CMS - Type safety — TypeScript throughout
- Performance — ship zero JavaScript by default
Astro checks every box. It’s a static site generator that ships HTML first and only hydrates interactive components when explicitly told to.
The Stack
- Astro — static site generation with content collections
- Tailwind CSS — utility-first styling with custom theme tokens
- TypeScript — type-safe frontmatter schemas
- GitHub Pages — free, reliable hosting
Content Collections
Astro’s content collections are the standout feature. You define a schema:
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
date: z.coerce.date(),
description: z.string(),
tags: z.array(z.string()).optional(),
category: z.string(),
}),
});
Then every markdown file in src/content/blog/ is validated against it at build time. No runtime surprises.
Design Language
The visual system follows a zen minimalist aesthetic:
- Dark/light theming via CSS custom properties and
localStorage - Dot grid backgrounds using
radial-gradient - Generous whitespace — let the content breathe
- Uppercase, letter-spaced labels for navigation and section headers
- Subtle transitions — small transforms on hover, gentle opacity shifts
Deployment
A single GitHub Actions workflow handles everything:
- Push to
main - Actions installs dependencies and runs
astro build - Output is deployed to GitHub Pages
The entire build takes under 30 seconds.
Takeaways
Astro is the right tool for content-focused sites. It gets out of your way, produces fast output, and the developer experience is excellent.
If you’re building a personal site, portfolio, or blog — give it a look.
The source code for this site is available on GitHub.