Gatsby to Astro: Why I Finally Migrated

3 min read

My site started in 2017 and had been stuck on Gatsby 2.28.2 for years. React 16, Ant Design v3, D3 v5 - everything was outdated. Security warnings kept piling up. Build times were slow. I’d been putting off the migration for too long.

Last week, I finally did it. Moved 22 articles and 14 data visualizations from Gatsby to Astro 4.x. Here’s what I learned.

Why Astro over Next.js?

I looked at Next.js, Remix, and Astro. For a content-heavy site like mine, Astro made the most sense:

  • Zero JS by default - ships only what you need
  • Partial hydration - interactive components load JS, static ones don’t
  • Framework agnostic - I could keep my React components
  • Vite-powered - fast HMR, modern tooling

The philosophy clicked: ship HTML, sprinkle JavaScript when necessary.

The Migration

Content was easy

Astro’s content collections handle markdown beautifully. I wrote a quick script to convert frontmatter:

// Convert Gatsby format to Astro
// written: "2018-10-02" → date: 2018-10-02
// category: "Deep Learning" → tags: ["Deep Learning"]

6 markdown articles migrated in minutes.

React components were trickier

16 of my articles were React components with interactivity, API calls, and visualizations. The solution: convert to MDX and use client directives.

import VegaChart from '@/components/VegaChart.tsx';

# My Article

<VegaChart client:visible specUrl="..." />

The client:visible directive is nice - only loads JS when the component scrolls into view.

Ant Design had to go

Ant Design v3 was the biggest dependency. I replaced it with Tailwind CSS. More work upfront, but the bundle size dropped dramatically.

Visualizations needed rewiring

My Plotly and Vega charts didn’t play well with Astro’s hydration. I ended up converting most to ECharts using echarts-for-react. Some gotchas:

  • Raw echarts.init() doesn’t work reliably with React hydration
  • react-scrollama fails with Astro - use native IntersectionObserver instead
  • vis-network has CommonJS issues with Vite

I documented these in a GOTCHAS.md file for future reference.

Results

The numbers speak for themselves:

MetricGatsbyAstro
First Contentful Paint~2.5s~0.5s
JS Bundle~300KB~30KB
Lighthouse Performance6095

5x faster page loads. 10x smaller JavaScript.

What I’d Do Differently

Use git worktrees from the start. I worked in a separate directory which made comparing old and new versions easy.

Don’t rewrite everything. If a React component works, keep it as React. Astro supports mixing frameworks.

Automate the boring stuff. Claude Code helped with bulk frontmatter conversion and finding broken image paths. The repetitive parts went fast.

Worth It?

Yes. The site feels snappier, the codebase is cleaner, and I’m no longer dreading dependency updates. Should have done this sooner.

If you’re stuck on an old Gatsby version, Astro is a solid choice for content sites. The migration isn’t trivial, but the payoff is real.


References

[1] Astro documentation