Building My Portfolio with Astro: A Developer's Journey
How I built this photography portfolio website using Astro, React, and modern web technologies - and what I learned along the way.
Why Astro for a Photography Portfolio?
When I decided to create a website to showcase my photography journey, I had several requirements:
- Fast loading images (crucial for a photography site)
- Static generation for optimal performance
- Component flexibility to mix different frameworks as needed
- Content management that doesn’t require a complex CMS
- Modern developer experience with TypeScript support
After researching options, Astro checked all these boxes and more.
The Architecture Decision
Multi-Page vs. Single-Page App
Instead of building a complex SPA, I chose a multi-page architecture:
- Homepage: Main portfolio with project showcases
- Gallery: Photo collection with interactive carousel
- Challenge: 30-day progress tracker
- Blog: Content sharing and reflections
This approach gives each section its own focused purpose while maintaining fast navigation between pages.
Content Collections: A Game Changer
One of Astro’s standout features is Content Collections. Instead of managing content in JSON files or a headless CMS, I can write markdown files with type-safe frontmatter:
// src/content/config.ts
const blog = defineCollection({
type: "content",
schema: z.object({
title: z.string(),
description: z.string(),
publishDate: z.date(),
heroImage: z.string().optional(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
This gives me TypeScript intellisense for all my content and catches errors at build time.
Technical Implementation Highlights
Photo Gallery with Swiper.js
For the gallery, I needed something that could handle high-resolution images gracefully. Swiper.js provided:
- Touch-friendly navigation for mobile users
- Lazy loading for performance
- Zoom functionality for detailed viewing
- Thumbnail navigation for quick browsing
const mainSwiperConfig = {
modules: [Navigation, Pagination, Thumbs, Zoom],
spaceBetween: 10,
navigation: true,
zoom: true,
// ... more config
};
Component Strategy
I used a hybrid approach with components:
- Astro components for layout and static content
- React components for interactive features (gallery, challenge tracker)
- Custom CSS variables for consistent theming
This allows for selective hydration—only the interactive parts load JavaScript.
Image Optimization
Astro’s image optimization is fantastic for a photography site:
---
import { Image } from "astro:assets";
---
<Image src={photo.image} alt={photo.title} width={800} height={600} loading="lazy" />
This automatically generates optimized WebP versions and responsive sizes.
Development Workflow
Content Creation
Adding new photos or blog posts is as simple as creating a markdown file:
---
title: "Golden Hour Cityscape"
captureDate: 2025-01-10T18:30:00Z
camera: "Canon EOS R6"
settings:
aperture: "f/8"
shutter: "1/250"
iso: "200"
tags: ["cityscape", "golden-hour"]
---
This shot was taken during my 5th day of the challenge...
Type Safety
The Content Collections provide full TypeScript support, so I get autocomplete and error checking for all content:
const allPosts = await getCollection("blog");
const publishedPosts = allPosts
.filter((post) => !post.data.draft)
.sort((a, b) => new Date(b.data.publishDate).getTime() - new Date(a.data.publishDate).getTime());
Performance Results
The static generation approach delivers excellent results:
- Build time: ~3 seconds for the entire site
- Lighthouse scores: 95+ across all metrics
- Bundle size: Under 200KB for JavaScript
- Image loading: Lazy loading with WebP optimization
Lessons Learned
1. Start Simple, Add Complexity Gradually
I began with basic pages and added features like the photo gallery incrementally. This prevented overwhelming complexity early on.
2. Content Collections Are Powerful
The type-safe content management eliminated entire categories of bugs and made content creation enjoyable.
3. Static Sites Don’t Mean Static Experiences
With selective hydration, I can have rich interactions (image galleries, progress trackers) while maintaining performance.
4. Developer Experience Matters
Astro’s dev server with hot reloading and TypeScript support made the development process smooth and enjoyable.
What’s Next
Some features I’m considering for future iterations:
- Search functionality for blog posts and photos
- Comment system for blog engagement
- RSS feed for blog subscribers
- Progressive enhancement for offline viewing
The Photography Connection
Building this portfolio has reinforced something important: both photography and web development are about creating experiences. Whether I’m composing a photo or architecting a website, I’m thinking about how someone will interact with and experience my work.
The technical skills transfer in unexpected ways—understanding composition in photography helps with visual design decisions, and the systematic approach to learning development translates well to learning photography fundamentals.
Interested in the technical details? The source code for this site showcases modern Astro patterns and could be a useful reference for your own projects.