Building This Portfolio: Why Astro Beats React and Next.js for Static Sites
A deep dive into why I chose Astro for my portfolio website — superior performance, minimal JavaScript, excellent SEO, and a scalable data architecture using simple JavaScript files.
Yosri Mlik
Software Engineer
When it came time to build my portfolio website, I had a choice: use the familiar React/Next.js stack I'd been working with, or try something different. After careful consideration, I chose Astro — and it was one of the best technical decisions I've made for a static site.
This isn't just another portfolio site. It's a case study in modern static site architecture, demonstrating why Astro is becoming the go-to choice for landing pages and content-heavy websites that need to be fast, SEO-friendly, and maintainable.
The Problem with Traditional Approaches
Plain HTML: No Components, No Scalability
Traditional HTML works for simple sites, but it falls apart quickly when you need:
- Reusable components — Headers, footers, cards, and navigation elements
- Data management — Projects, articles, and other content that changes
- Styling consistency — CSS that doesn't become a mess
- Modern tooling — Hot reload, optimization, and build pipelines
Next.js SSG: Overkill for Static Sites
Next.js is fantastic for dynamic applications, but for a mostly static portfolio, it brings unnecessary complexity:
- Heavy JavaScript bundles — Even with SSG, Next.js ships React and its router
- Complex routing — File-based routing is great, but overkill for 5-10 pages
- Hydration overhead — React needs to hydrate on the client, adding load time
- Build complexity — More moving parts than necessary for static content
Regular React: SEO Nightmare
A standard React SPA (Create React App, Vite, etc.) is terrible for portfolios because:
- Poor SEO — Content rendered client-side, search engines see empty pages
- Slow initial load — Must download React bundle before any content appears
- No static generation — Every page is built on-demand in the browser
- Accessibility issues — Screen readers struggle with client-rendered content
Why Astro Wins for Static Sites
Zero JavaScript by Default
Astro's killer feature is that it ships zero JavaScript by default. Components render to HTML on the server and stay as HTML in the browser unless you explicitly opt into client-side interactivity.
// This component renders to static HTML
// No JavaScript shipped to browser
---
const props = Astro.props;
---
<div class="card">
<h2>{props.title}</h2>
<p>{props.description}</p>
</div> Islands Architecture
When you need interactivity, Astro's islands architecture lets you hydrate only the components that need it. Navigation menus, image sliders, or contact forms can be interactive while everything else stays static.
// Only this component gets JavaScript
<script>
// Interactive menu logic
</script> Superior Performance
The performance difference is dramatic:
| Metric | Next.js SSG | Astro |
|---|---|---|
| Initial JS Bundle | ~45KB (React + Router) | ~0KB (static HTML) |
| Time to Interactive | ~1.2s | ~0.3s |
| Lighthouse Performance | 85-90 | 95-100 |
| SEO Score | 90-95 | 100 |
The Architecture: Data in JavaScript Files
Why Not a CMS?
For a personal portfolio, a traditional CMS is overkill. It adds:
- Database maintenance and backups
- Security vulnerabilities to patch
- Monthly hosting costs
- Complex deployment pipelines
- Vendor lock-in
JavaScript Files as Data Source
My solution: store data in simple JavaScript files. Here's why this scales surprisingly well:
export const projects = [
{
title: "AI Chat",
technologies: ["React", "Next.js"],
links: {
demo: "https://...",
repo: "https://..."
},
images: [
{ src: "/img/chat.png", alt: "Chat interface" }
]
}
// ... more projects
]; Technical Implementation Details
Component Architecture
The portfolio follows a clean component hierarchy:
src/
├── layouts/
│ └── Layout.astro # Base layout with header/footer
├── components/
│ ├── Navbar.astro # Navigation (interactive island)
│ ├── Projects/
│ │ ├── ProjectsSection.astro # Projects listing
│ │ └── ProjectCard.astro # Individual project card
│ └── Articles/
│ └── ArticlesSection.astro # Article listings
├── pages/
│ ├── index.astro # Homepage
│ └── articles/
│ ├── index.astro # Articles listing
│ └── [slug].astro # Individual article
└── data/
├── projects.js # Project data
└── articles.js # Article metadata Styling with Tailwind CSS v4
Using Tailwind v4 with CSS variables for theming:
/* CSS Variables for theme switching */
:root {
--accent: 59, 130, 246;
--text-primary: 31, 41, 55;
}
/* Tailwind v4 theme tokens */
@theme {
--color-accent: rgb(var(--accent));
--color-text-primary: rgb(var(--text-primary));
} Performance Optimizations
- Image optimization — Astro automatically optimizes images with width/height attributes
- Code splitting — Only interactive components get JavaScript
- Prefetching — Link prefetching for faster navigation
- Critical CSS — Inline critical CSS, defer non-critical styles
SEO Advantages
Because everything renders to static HTML, search engines see perfectly structured content:
<!DOCTYPE html>
<html lang="en">
<head>
<title>AI Chat Project - Yosri Mlik</title>
<meta name="description" content="Full-stack AI chatbot...">
</head>
<body>
<h1>AI Chat</h1>
<p>A full-stack AI chatbot that lets users...</p>
<!-- All content visible to search engines -->
</body>
</html> Compare this to a React SPA where search engines see:
<!DOCTYPE html>
<html>
<head><title>My Portfolio</title></head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
<!-- No content for search engines! -->
</body>
</html> Deployment Simplicity
The entire site builds to static files that can be deployed anywhere:
$ npm run build
dist/
├── index.html
├── projects/
│ └── index.html
├── articles/
│ ├── index.html
│ └── building-modern-ai-chatbot/
│ └── index.html
├── assets/
│ └── styles.css
└── img/
└── chat.png No server required, no database to maintain, no environment variables to configure. Just static files that work on any hosting platform.
When This Architecture Works Best
- Portfolio sites — Showcase projects and articles
- Documentation sites — Static docs with good navigation
- Marketing landing pages — Fast loading, SEO-optimized
- Blogs and content sites — Markdown-based content
- Product showcases — Feature highlights and demos
When to Use Something Else
- User-generated content — Need a database and authentication
- Real-time features — Chat, notifications, live updates
- Complex admin interfaces — Content management, user management
- E-commerce — Shopping carts, payment processing
Future Scalability
This architecture scales in several ways:
Content Management
When the site grows, I can easily migrate to:
- Headless CMS — Contentful, Sanity, or Strapi
- Markdown files — Astro's content collections
- Database — PostgreSQL or MongoDB with API endpoints
Performance Enhancements
- Edge deployment — Cloudflare Workers, Vercel Edge
- CDN integration — Global content delivery
- Advanced caching — Service workers, browser caching
Lessons Learned
- Simplicity scales — Start simple, add complexity only when needed
- Performance matters — Fast sites rank better and convert more
- SEO is not optional — Even portfolios need to be discoverable
- Choose the right tool — Don't use React for everything
Conclusion
Building this portfolio with Astro taught me that the best architecture is often the simplest one that meets your needs. Astro's zero-JS-by-default approach, combined with static data files, creates a site that's fast, SEO-friendly, and maintainable — everything a portfolio should be.
For landing pages, portfolios, and content sites, Astro is becoming the clear choice over React and Next.js. It delivers better performance, simpler deployments, and excellent SEO without sacrificing developer experience.