Skip to content

refactor: migrate to astro@6#28874

Merged
colbywhite merged 32 commits into
productionfrom
astro@6
Mar 17, 2026
Merged

refactor: migrate to astro@6#28874
colbywhite merged 32 commits into
productionfrom
astro@6

Conversation

@colbywhite
Copy link
Copy Markdown
Collaborator

@colbywhite colbywhite commented Mar 9, 2026

Migrate to Astro 6 (Beta)

Reference links:

This change is mostly focused around migrating to zod@4 since this project doesn't use the Cloudflare adapter.

What Changed

1. Package Upgrades

Package Before After
astro 5.13.7 6.0.5
@astrojs/check 0.9.4 0.9.8
@astrojs/react 4.2.5 5.0.0
@astrojs/rss 4.0.12 4.0.17
@astrojs/sitemap 3.5.1 3.7.1
@astrojs/starlight 0.37.6 0.38.1
@astrojs/starlight-docsearch 0.6.0 0.7.0
@astrojs/starlight-tailwind 4.0.1 5.0.0
starlight-image-zoom 0.13.0 0.14.1
starlight-links-validator 0.17.2 0.20.1
starlight-package-managers 0.11.0 0.12.0
starlight-showcases 0.3.0 0.3.2
starlight-scroll-to-top 0.4.0 0.4.0
astro-breadcrumbs 3.3.1 3.4.0
eslint-plugin-astro 1.3.1 1.6.0

2. Schema Import Migration: astro:schemaastro/zod

Astro 6 deprecates the astro:schema virtual module in favor of astro/zod. All 18 schema files in src/schemas/ were
updated:

-import { z } from "astro:schema";
+import { z } from "astro/zod";

3. Zod 4 API Migrations

Zod 4 introduces several breaking changes that required updates to our schema definitions:

a. Stricter .record() type signatures

Before (Zod 3): z.record(valueSchema) — key type was implicitly string
After (Zod 4): z.record(keySchema, valueSchema) — both key and value types must be explicit

-text: z.union([z.string(), z.record(z.string())]),
+text: z.union([z.string(), z.record(z.string(), z.string())]),
-const linkHTMLAttributesSchema = z.record(
+const linkHTMLAttributesSchema = z.record(
+	z.string(),
 	z.union([z.string(), z.number(), z.boolean(), z.undefined()]),
 );

b. .default({}).prefault({})

Zod 4 removes the ability to call .default({}) on objects that haven't been explicitly created via .object(). The
replacement is .prefault({}), which preserves the same runtime behavior while being type-safe.

-	.default({})
+	.prefault({})

c. .passthrough().looseObject()

Zod 4 deprecates .passthrough() in favor of .looseObject(), which is more explicit about allowing unknown keys.

-export const BadgeComponentSchema = badgeSchema
-	.extend({
-		size: z.enum(["small", "medium", "large"]).default("small"),
-	})
-	.passthrough();
+export const BadgeComponentSchema = z.looseObject({
+	...badgeSchema.shape,
+	size: z.enum(["small", "medium", "large"]).default("small"),
+});

d. .function().args(...).returns(...).function({ input: [...], output: ... })

Zod 4 changes the function schema builder API to use an object syntax:

-z.function()
-  .args(z.object({ ... }))
-  .returns(z.boolean())
+z.function({
+  input: [z.object({ ... })],
+  output: z.boolean(),
+})

BaseSchemaProperties Component: Migrating from Zod Internals to JSON Schema

The BaseSchemaProperties.astro component renders documentation for our frontmatter schema fields (used in
/style-guide/frontmatter/). It introspects Zod schemas to extract field names, types, descriptions, and allowed
values. Much of the introspection tools are different or don't exist in zod@4.

Instead of introspection, which couples the page to zod's internal structure, JSON schema is used to build the page.
JSON schema is a first-class citizen in zod@4.

4. Frontmatter Schema: From Strict Unions to Flexible Strings

The original schema declaration for pcx_content_type and difficulty simultaneously validated against a strict set of
allowed values and allowed all values. The contradiction was resolved by just allowing all strings, removing the
union validation.

This isn't related to astro@6. This is always been a contradiction. zod@4migration was just the catalyst
since the use of .catch breaks the JSON schema logic above.

5. Red-herring shift to :global for Scoped Styles

There was an Astro bug (withastro/astro#15907) related to scoped styles that cropped up due to the project's
tendency to attempt to apply styles across components, most commonly styling internal classes of Starlight. Before
I realized there was an Astro bug, I was attempting to solve these issues by using the recommended
is:global/:global (i.e. global styles). Once I found the bug (and the subsequent fix to the big in
@astrojs/compiler@3.0.1), these global-related fixes weren't needed.

But the reason why the bug affected this project in the first place is due to the lack of :global. So I kept them
in. However, Footer.astro's version of the bug was kept around because I was using that as a test to make sure
@astrojs/compiler@3.0.1 truly fixed the styling issues. (It did.)

Testing

  • npm run check passes (Astro + Worker type checking)
  • npm run lint passes
  • npm run format:core:check passes

Example URLS to compare

Do not limit testing to these URLs.

Route Prod env Preview env
/changelog/2026-02-15-workers-best-practices/ URL URL
/workers/examples/read-post/ URL URL
/workers/examples/turnstile-html-rewriter/ URL URL
/images/tutorials/optimize-user-uploaded-image/ URL URL

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 9, 2026

This pull request requires reviews from CODEOWNERS as it changes files that match the following patterns:

Pattern Owners
* @cloudflare/pcx-technical-writing
package.json @cloudflare/content-engineering
*.astro @cloudflare/content-engineering, @kodster28
*.ts @cloudflare/content-engineering, @kodster28

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 10, 2026

@colbywhite colbywhite marked this pull request as ready for review March 16, 2026 17:32
@colbywhite colbywhite requested review from a team and kodster28 as code owners March 16, 2026 17:32
@colbywhite colbywhite requested a review from a team March 16, 2026 17:32
@colbywhite colbywhite marked this pull request as draft March 16, 2026 17:49
@colbywhite colbywhite marked this pull request as ready for review March 17, 2026 17:12
@colbywhite colbywhite merged commit dce2371 into production Mar 17, 2026
11 checks passed
@colbywhite colbywhite deleted the astro@6 branch March 17, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment