After years of running my portfolio on Jekyll, I recently made the decision to migrate to Astro. As a designer who codes, I wanted to share my experience and the reasoning behind this architectural shift.
Why Leave Jekyll?
Don’t get me wrong, Jekyll served me well for years. My previous setup was solid:
- Ruby-based static site generator
- Liquid templating for dynamic content
- Collections for portfolio items and blog posts
- Tailwind CSS for styling (added later)
- Cloudinary for image optimization
- Netlify for hosting and deployment
But as my needs evolved, I started hitting some friction points:
1. Ruby Dependencies Hell
Managing Ruby versions, gems, and dependencies became increasingly painful. Every time I wanted to make a quick update, I’d spend 20 minutes just getting the local environment running again.
2. Limited Modern JavaScript Integration
While Jekyll could handle basic JavaScript, integrating modern frameworks or libraries felt clunky. I wanted better TypeScript support and modern tooling.
3. Templating Limitations
Liquid templating, while powerful, felt restrictive compared to component-based approaches. I found myself writing repetitive code and struggling with complex data transformations.
4. Performance Concerns
Build times were getting longer, and I wanted better control over bundle optimization and code splitting.
Why Choose Astro?
After researching alternatives (Next.js, Nuxt, SvelteKit), Astro emerged as the perfect fit for my needs:
✅ Zero JavaScript by Default
Astro’s “islands architecture” means you only ship JavaScript when you actually need it. Perfect for a portfolio site that’s mostly static content.
✅ Component-Based Architecture
.astro files combine the best of JSX and templating, making components reusable and maintainable:
---
// Component logic in frontmatter
const { title, excerpt } = Astro.props;
---
<article class="blog-card">
<h3>{title}</h3>
<p>{excerpt}</p>
</article>
✅ Framework Agnostic
Can use React, Vue, Svelte, or vanilla JavaScript components as needed. Great for gradual adoption or mixing frameworks.
✅ Modern Tooling
Built on Vite, with excellent TypeScript support, hot module replacement, and modern build optimizations out of the box.
✅ Content Collections
Astro’s content collections provide type-safe frontmatter and better organization than Jekyll’s collections:
// src/content/config.ts
export const collections = {
blog: defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
date: z.date(),
excerpt: z.string(),
tags: z.array(z.string()).optional(),
}),
}),
};
The Migration Process
1. Content Migration
Moving from Jekyll’s _posts and collections/_portfolio to Astro’s src/content/ structure:
Jekyll Structure:
collections/
_posts/
2025-07-30-designing-for-scale-brighthr.md
_portfolio/
bubblebabysitting.md
Astro Structure:
src/content/
blog/
designing-for-scale-brighthr.md
portfolio/
bubblebabysitting.md
The frontmatter mostly transferred directly, but I had to update some Liquid-specific syntax.
2. Template Conversion
Converting Liquid templates to Astro components was the biggest undertaking:
Jekyll (Liquid):
{% for post in site.posts limit: 3 %}
<article>
<h3>{{ post.title }}</h3>
<p>{{ post.excerpt | strip_html | truncate: 160 }}</p>
</article>
{% endfor %}
Astro:
---
const posts = await getCollection('blog');
const recentPosts = posts.slice(0, 3);
---
{recentPosts.map(post => (
<article>
<h3>{post.data.title}</h3>
<p>{post.data.excerpt}</p>
</article>
))}
3. Data Migration
Jekyll’s _data folder became Astro’s src/data/, with YAML files converted to JavaScript:
Jekyll (_data/tools.yaml):
design:
title: "Design"
items:
- name: "Sketch"
link: "https://sketch.com"
Astro (src/data/tools.js):
export const toolsData = {
design: {
title: "Design",
items: [
{ name: "Sketch", link: "https://sketch.com" }
]
}
};
4. Styling Migration
Thankfully, my Tailwind CSS classes transferred directly. The main change was moving from Jekyll’s asset pipeline to Vite’s handling of CSS and static assets.
Challenges and Solutions
Challenge 1: TypeScript Strictness
Astro’s TypeScript checking caught several issues that Jekyll’s Liquid templating missed.
Solution: Properly type interfaces and use content collection schemas for type safety.
Challenge 2: Build Configuration
Moving from Jekyll’s _config.yml to Astro’s astro.config.mjs required understanding Vite and Astro’s plugin ecosystem.
Solution: Start with a minimal config and gradually add features like Cloudinary integration and Tailwind.
Challenge 3: Deployment Changes
Jekyll builds on Netlify were straightforward. Astro required understanding Node.js build processes.
Solution: Astro’s Netlify adapter made this seamless once configured properly.
Challenge 4: Content Collection Caching
During development, content changes weren’t always reflected immediately.
Solution: Delete the .astro cache directory when content collection schemas change: rm -rf .astro
Performance Improvements
The migration yielded impressive performance gains:
- Build Time: ~45 seconds → ~8 seconds
- Bundle Size: 40% smaller JavaScript bundles
- Lighthouse Score: 95 → 100 (Performance)
- Hot Reload: Near-instant vs 3-5 seconds in Jekyll
Lessons Learned
Start with Content
Migrate content first, then build components around it. This helped maintain the existing information architecture while modernizing the presentation layer.
Embrace the Component Mindset
Breaking Jekyll partials into proper Astro components improved reusability and maintenance. Each component now has clear props and responsibilities.
Leverage TypeScript
Even as a designer, TypeScript caught numerous errors and improved the development experience. Content collection schemas are particularly valuable for catching frontmatter inconsistencies.
Gradual Enhancement
Astro’s islands architecture allowed me to add interactivity progressively. The contact modal, AOS animations, and image zoom features could be enhanced without affecting the base performance.
The Result
My new Astro-powered portfolio is:
- ⚡ Faster - Better performance and build times
- 🛠️ More Maintainable - Component-based architecture
- 🔒 Type-Safe - Fewer runtime errors
- 🚀 Future-Proof - Modern tooling and ecosystem
Should You Migrate?
Consider Astro if you:
- Want better performance and modern tooling
- Prefer component-based architecture over templating
- Need TypeScript support
- Want framework flexibility
- Are comfortable with Node.js ecosystem
Stick with Jekyll if:
- You’re happy with Ruby/Liquid ecosystem
- Your site is simple and stable
- You don’t need modern JavaScript features
- Migration effort doesn’t justify benefits
Resources for Migration
- Astro Documentation
- Content Collections Guide
- Jekyll to Astro Migration Guide
- My Migration Commit History (for reference)
The migration took about two weeks of evening work, but the result was worth it. Astro strikes the perfect balance between static site simplicity and modern development experience.
Have questions about migrating from Jekyll to Astro? Feel free to reach out - I’m happy to help fellow designers make the transition.