Skip to content
All posts

Rebuilding my portfolio with Astro, Keystatic and Bun

Why I rebuilt my hand-crafted 2021 portfolio as a statically generated Astro site with a local Keystatic CMS, native view transitions, and a one-click git publish flow.

Astro Keystatic meta

My first portfolio was hand-written HTML, CSS and JavaScript — every animation keyframe typed out by hand, Materialize CSS holding the layout together, and a service worker bolted on at the end. It served me well for five years. But it was time.

What the new stack looks like

The new site is a bun monorepo with two apps:

  • apps/web — an Astro site, statically generated, deployed on Cloudflare Pages
  • apps/cms — a local Keystatic studio that writes MDX straight into the web app’s content folder

Content lives in MDX files with frontmatter, so the whole site builds to plain HTML — every route gets its own index.html at build time:

const blog = defineCollection({
  loader: glob({
    pattern: '**/index.mdx',
    base: './src/content/blog',
  }),
  schema: (ctx) => z.object(articleFields(ctx)),
});

The fun parts

  1. Native view transitions make every navigation feel like one continuous surface
  2. Dark and light themes share one palette of CSS variables — even the code blocks switch between VS Code’s two default themes
  3. Every page is plain pre-rendered HTML, yet the whole site still feels app-smooth

More on each of those soon. This post itself was written in the new CMS — and published with a single button that commits and pushes the markdown to git.