Skip to content

Upgrading Astro to Version 5

by Christian Praß

Upgrading Astro is usually a great experience due to the vast tooling available. There are separate upgrade guides available and there even exists an upgrade tool that takes care of the necessary package dependency upgrades. Let’s run that.

npx @astrojs/upgrade

 astro   Integration upgrade in progress.

  @astrojs/check is up to date on v0.9.4
  @astrojs/sitemap is up to date on v3.2.1
  @astrojs/rss will be updated from v4.0.9 to v4.0.11
  astro will be updated  from v4.16.16 to v5.2.3 
  @astrojs/mdx will be updated  from v3.1.9 to v4.0.8 
  @astrojs/netlify will be updated  from v5.5.4 to v6.1.0 
  @astrojs/react will be updated  from v3.6.3 to v4.2.0 

I also ran a full dependency upgrade to move to React 19 using npx npm-check-updates -u which worked surprisingly well.

That was only the first step, though. https://docs.astro.build/en/guides/upgrade-to/v5/ tells us that Astro now uses vite v6.0 and that comes with it’s own set of breaking changes. I had to get rid of the @vite-pwa/astro, simply because it doesn’t seem to support Astro v5 yet. I’m not using most of the PWA features and the manifest can be added manually.

No more hybrid mode

We now only have static and server modes and we can opt out from static renderin any time which is a great improvement.

The Content Collections API is now considered “legacy”

This is by far the biggest change for me, I knew this was coming and it was surprisingly easy to move to the new Content Layer API, which is supposed to be faster, more versatile and hopefully longer lasting than the old one. I follwed the steps outlined in the guide.

  1. Moving the src/content/config.ts file to src/content.config.ts.
  2. Replacing type: 'content' with the loader pattern in content.config.ts.
    loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content/blog" }),
  3. Replace the use of post.slug with post.id wherever I load posts.
  4. Replace post.render() with render(post) as posts are now plain objects without a render method.

For the sake of future me I did all that, knowing that I didn’t have to, because there is a legacy mode available.

I noticed that my custom slugs still work. I used the slug frontmatter field for that and now Astro automatically picks that as id overwrite. Lucky me! One thing to keep in mind is that the content loader does not guarantee the same order of entries as the legacy loader, so sorting is always a good idea.