technical

First Look at Astro 5: What Actually Changed

· technical

Astro 5 shipped with a lot of fanfare. “Content Layer,” “Server Islands,” “Vite 6 under the hood.” I spent a week actually using it before writing a word.

Content Layer is Real

The old content collections worked fine for small sites. Content Layer works for large ones. The new loader API lets you pull content from anywhere — a CMS, a database, a remote JSON file — and it all compiles to the same static output. For a site like this, the difference is minimal. For a site with 10,000 posts, it matters.

import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const blog = defineCollection({
  loader: glob({ pattern: '**/*.mdx', base: './src/content/blog' }),
  schema: z.object({
    title: z.string(),
    date: z.date(),
    category: z.enum(['technical', 'health', 'political', 'food']),
  }),
});

Server Islands: Overhyped for Static Sites

Server Islands let you mark a component as server-rendered inside an otherwise static page. Think: a static blog post with a live comment count widget. The concept is sound. For a pure static site like StreetStack, it’s irrelevant. If you’re on static output, skip this whole section.

The Footgun: Date Handling

Frontmatter dates. Astro 5 with Content Layer parses them differently than Astro 4. If you have date: 2026-05-10 in your frontmatter, you now get a Date object, not a string. Any component doing .toLocaleDateString() directly on a string will silently break.

Fix: always convert explicitly.

const formattedDate = new Date(post.data.date).toLocaleDateString('en-US', {
  year: 'numeric', month: 'long', day: 'numeric'
});

Verdict

Upgrade if you’re starting fresh. Migration from Astro 4 takes about a day and is mostly mechanical. The DX improvements are real. The performance improvements at scale are real. The marketing hype around Server Islands is aimed at a different use case than static blogs.

#astro#javascript#web