Project summary
Built a static, recruiter-first portfolio site with Astro and MDX, designed to showcase technical decision-making with minimal client-side JavaScript. Projects are defined via a strict content schema and rendered through dynamic routes backed by Astro content collections, enabling consistent write-ups and eliminating ad-hoc page wiring.
Problem
Most portfolio sites fail at the thing hiring managers actually need: fast proof of scope, ownership, and engineering judgment. Typical issues:
Content is inconsistent across projects (no enforced structure).
Pages are JS-heavy and slow on mobile.
Adding a project requires bespoke page work, which discourages updates.
Goal: a site that loads instantly, reads cleanly, and makes it trivial to publish high-signal project write-ups.
Constraints
Static-only output (output: “static”) for predictable hosting and performance.
Minimal JavaScript; default to server-rendered/static HTML and system fonts.
Content must be validated at build time via a strict schema (no “optional but missing” fields).
Solo-maintained: low operational overhead, easy to update from raw notes.
Hosting target: Cloudflare Pages (simple CI, CDN by default).
Approach
Use Astro as a static site generator and treat project write-ups as typed content, not pages. MDX provides a flexible writing surface, while Astro content collections enforce required metadata and enable deterministic routing.
Define a projects content collection with a strict schema (title/summary/role/stack/status/year).
Render project pages via src/pages/projects/[slug].astro using content collection lookups and static path generation.
Keep the UI intentionally plain: system fonts, static HTML, minimal JS, and simple navigation optimized for scanning.
System overview
Content layer: src/content/projects/*.mdx entries validated against src/content/config.ts.
Build layer: Astro builds static HTML for home and each /projects/[slug] route.
Routing: Dynamic project route maps slugs to content entries; missing slugs return 404.
Presentation: Shared BaseLayout.astro provides consistent page structure; home pulls from the projects collection and links to detail pages.
Deployment target: Cloudflare Pages serving the built dist/ output.
Tradeoffs and decisions
Astro over React/Next.js: Chose static generation and partial hydration to avoid unnecessary client-side JS and runtime complexity.
Content collections over CMS: Build-time validation and versioned content in Git keep the system simple and auditable.
Strict schema enforcement: Forces completeness and consistency at the cost of slightly higher friction when adding a project.
No design system (yet): Plain layouts prioritize clarity and speed over visual polish.
Static hosting on Cloudflare Pages: Eliminates server management and provides global CDN by default, with limited runtime flexibility.
What I’d improve next
Add a /resume page with embedded PDF and download link.
Introduce lightweight visual hierarchy and spacing improvements without increasing JS payload.
Add automated Lighthouse checks in CI to catch performance regressions.
Expand project entries with diagrams or code excerpts where they materially improve understanding.