After years running my portfolio on Jekyll, I finally pulled the trigger and migrated to Astro. As a designer who codes (or is it a developer who designs? I still can’t decide), I figured I’d document the process and share what I learned.
Why leave Jekyll?
Jekyll served me well. Really well, actually. My setup was solid:
- Ruby-based static site generator
- Liquid templating
- Collections for portfolio and blog content
- Tailwind CSS for styling
- Cloudinary for images
- Netlify for hosting
But over time, friction points started piling up:
1. Ruby dependency hell
Every time I wanted to make a quick edit—update a blog post, tweak some styles—I’d spend 20 minutes just getting my local environment running again. Ruby versions, gem conflicts, bundler updates…it got old fast.
2. Modern JavaScript felt bolted on
Jekyll handles basic JavaScript fine, but integrating modern frameworks or libraries? Clunky. I wanted better TypeScript support and wasn’t getting it.
3. Liquid templating limitations
Powerful enough for what it does, but restrictive compared to component-based approaches. I found myself writing repetitive code and fighting with complex data transformations.
4. Build times creeping up
Performance wasn’t terrible, but I wanted more control over bundle optimization and code splitting.
Why Astro?
I looked at the usual suspects—Next.js, Nuxt, SvelteKit. But Astro felt like the right fit.
✅ Zero JavaScript by default
Astro’s “islands architecture” means you only ship JavaScript when you actually need it. For a mostly-static portfolio? Perfect.
✅ Component-based everything
.astro files feel like JSX had a baby with HTML templating. Clean, intuitive, reusable:
---
const { title, excerpt } = Astro.props;
---
<article class="blog-card">
<h3>{title}</h3>
<p>{excerpt}</p>
</article>
✅ Framework agnostic
Use React, Vue, Svelte, or vanilla JavaScript as needed. You’re not locked in.
✅ Modern tooling
Built on Vite. TypeScript support out of the box. Hot module replacement. Fast builds. All the good stuff.
✅ Content collections
Type-safe frontmatter and better organization than Jekyll’s collections system:
// 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 to Astro’s src/content/ was straightforward:
Jekyll:
collections/
_posts/
2025-07-30-designing-for-scale-brighthr.md
_portfolio/
bubblebabysitting.md
Astro:
src/content/
blog/
designing-for-scale-brighthr.md
portfolio/
bubblebabysitting.md
Frontmatter mostly transferred directly, although I had to strip out Liquid-specific syntax.
2. Template conversion
This was the big one. Converting Liquid templates to Astro components:
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 src/data/, with YAML 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
Tailwind CSS transferred directly. The main change was switching from Jekyll’s asset pipeline to Vite’s handling of CSS and static assets.
Challenges (and how I solved them)
Challenge 1: TypeScript strictness
Astro’s TypeScript caught issues that Liquid had happily ignored.
Solution: Properly typed interfaces and content collection schemas. Annoying at first, but saved me from runtime errors.
Challenge 2: Build configuration
Moving from Jekyll’s _config.yml to Astro’s astro.config.mjs meant understanding Vite’s plugin system.
Solution: Started minimal, added features incrementally (Cloudinary integration, Tailwind, etc.).
Challenge 3: Deployment
Jekyll builds on Netlify were fire-and-forget. Astro required understanding Node.js build processes better.
Solution: Astro’s Netlify adapter handled most of it once configured properly.
Challenge 4: Content collection caching
During development, content changes sometimes didn’t show up immediately.
Solution: Delete the .astro cache when schemas change: rm -rf .astro
Performance improvements
The numbers don’t lie:
- 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
What I learned
Start with content
Migrate content first, build components around it. Kept my information architecture intact while modernizing the presentation.
Embrace components
Breaking Jekyll partials into proper Astro components improved reusability massively. Each component has clear props and responsibilities. No more spaghetti includes.
TypeScript is your friend
Even as a designer, TypeScript caught numerous mistakes. Content collection schemas especially—they catch frontmatter typos before they break your build.
Gradual enhancement
Astro’s islands let me add interactivity progressively. Contact modal, AOS animations, image zoom—all enhanced without tanking base performance.
The result
My Astro portfolio is:
- ⚡ Faster - Better performance, faster builds
- 🛠️ More maintainable - Component architecture beats includes
- 🔒 Type-safe - Fewer runtime explosions
- 🚀 Future-proof - Modern tooling, active ecosystem
Should you migrate?
Consider Astro if:
- You want better performance and modern tooling
- Component-based architecture appeals to you
- You need TypeScript support
- You want framework flexibility
- You’re comfortable with Node.js
Stick with Jekyll if:
- You’re happy with Ruby/Liquid
- Your site is simple and stable
- You don’t need modern JavaScript features
- Migration effort doesn’t justify the benefits
Resources I used
Migration took about two weeks of evening work. Worth it? Absolutely. Astro hits the sweet spot between static site simplicity and modern development experience.
Questions about migrating from Jekyll to Astro? Reach out—happy to help fellow designer-developers make the jump.