The default answer most developers give clients is “Next.js.” Often, it’s the wrong one.
Here’s how I think about the choice on real projects.
When I reach for Astro
- Marketing sites, landing pages, portfolios — anything that’s mostly content and a little interactivity
- Clients who plan to edit copy in a CMS and never touch the code again
- Projects where bundle size is the dominant performance win — restaurants, agencies, boutique brands
- Fast launches — shipping a mostly-static site in under two weeks
Astro’s zero-JS default is genuinely great for this category. A marketing site has no business shipping 200KB of React just to render a hero and a form.
When I reach for Next.js
- Dashboards and SaaS frontends where half the screen is interactive
- Apps that need server-side data mutations as a first-class citizen (App Router is really good here)
- Projects with existing React codebases or component libraries
I used to default to Next.js for marketing sites because “it’s the safe choice.” The result was always the same: 4s LCPs on mobile, a bloated bundle, and an annoyed client asking why their site felt slow.
Where Astro hurts
It’s not all wins:
- Hot reload on content collections can be flaky. Edit an MDX file, sometimes the dev server doesn’t notice until you restart.
- Hydration of heavy interactive components is clunkier than Next.js. If you have 15 interactive widgets on one page, you’ll find yourself reaching for
client:loadeverywhere and wondering why you didn’t just use Next.
The pitch that works
“Your site will load in under a second on a mid-range Android on 4G. That’s not true of most Next.js marketing builds.”
Clients understand speed. That’s usually enough.