Migrating a Portfolio Site to Astro
How and why I rewrote my portfolio from a jQuery HTML5 template to Astro — and what I learned along the way.
Why Astro?
After running the same HTML5 UP “Dimension” template for years, I decided it was time for a proper rewrite. The goals were:
- Faster load times — zero JS shipped by default
- Blog support — markdown-driven, no CMS needed
- Maintainable architecture — components, typed data, clean separation of concerns
- Same dark aesthetic — keep what works, modernize what doesn’t
Astro delivers all of this out of the box.
What Changed
The old site was a single index.html with jQuery handling navigation, a custom text animator, and article flip transitions. Content was hard-coded into HTML.
The new site:
- All content lives in typed JSON data files (
experience.json,projects.json) - Skills are loaded from
skills.json— already existed, just wired up properly - Each section is an isolated Astro component
- Blog posts are Markdown files in
src/content/articles/ - Zero jQuery — just a tiny vanilla JS snippet for the name reveal animation
The Blog System
This is just a Markdown file. Drop a .md file in src/content/articles/ with frontmatter:
---
title: "Your Title"
date: 2025-05-13
description: "One liner"
tags: ["tag1", "tag2"]
---
Astro Content Collections validates the frontmatter, generates the route at /blog/[slug], and renders it with full syntax highlighting. No config needed beyond the initial config.ts schema.
What Stayed
The sub-apps — /mealplanner, /cah, /wordwiz — are untouched vanilla JS apps. They live in public/ and are served directly by nginx, completely bypassing Astro’s build pipeline.
The Docker + nginx setup is largely unchanged. Astro outputs a static dist/ folder; the Dockerfile just COPYs that instead of the entire project root.