Skip to content
6 changes: 3 additions & 3 deletions src/content/docs/en/guides/content-collections.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,8 @@ defineCollection({
// Transform a date string (e.g. "2022-07-08") to a Date object
updatedDate: z.string().transform((str) => new Date(str)),

authorContact: z.string().email(),
canonicalURL: z.string().url(),
authorContact: z.email(),
canonicalURL: z.url(),
})
})
```
Expand Down Expand Up @@ -427,7 +427,7 @@ const authors = defineCollection({
loader: glob({ pattern: '**/*.json', base: "./src/data/authors" }),
schema: z.object({
name: z.string(),
portfolio: z.string().url(),
portfolio: z.url(),
})
});

Expand Down
51 changes: 51 additions & 0 deletions src/content/docs/en/guides/upgrade-to/v6.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,57 @@ Integration and adapter maintainers should pay special attention to changes affe
- [routes with percent-encoded percent signs (e.g. `%25`)](#removed-percent-encoding-in-routes)
- [`astro:ssr-manifest` virtual module](#removed-astrossr-manifest-virtual-module-integration-api)

### Zod 4

Astro v6.0 upgrades to Zod 4, a major dependency update that may require changes to custom Zod schemas in your project.

#### What should I do?

If you have custom Zod schemas in your `content.config.ts` or other configuration files, you'll need to update them for Zod 4. Refer to the [Zod migration guide](https://zod.dev/v4/changelog) for detailed changes in the Zod API.

Notably, many `string()` formats have been deprecated (e.g. `z.string().email()`, `z.string.url()`), and their APIs have been moved to the top-level z namespace. You may need to update how you validate form input for your Astro Actions:

```ts title="src/actions/index.ts" ins={8} del={7}
import { defineAction } from 'astro:actions';
import { z } from 'astro/zod';
export const server = {
newsletter: defineAction({
accept: 'form',
input: z.object({
email: z.string().email(),
email: z.email(),
terms: z.boolean(),
}),
handler: async ({ email, terms }) => { /* ... */ },
})
}
```

Additionally, if you use `.default()` with transforms, you may need to update your schemas. In Zod 4, default values must match the output type (after transforms), not the input type. The default value short-circuits parsing when the input is `undefined`:

```ts title="src/content.config.ts" del={5-6} ins={7-8}
import { z } from 'astro/zod';

const blog = defineCollection({
schema: z.object({
// Zod 3: default matched input type (string)
views: z.string().transform(Number).default("0"),
// Zod 4: default must match output type (number)
views: z.string().transform(Number).default(0),
})
});
```

For the old behavior where defaults are parsed, use the new `.prefault()` method.

You can ensure you're the same version of Zod that Astro uses internally by [importing Zod from `astro/zod`](#deprecated-astroschema-and-z-from-astrocontent).

```ts
import { z } from 'astro/zod';
```

<ReadMore>See more about [the `astro/zod` module](/en/reference/modules/astro-zod/).</ReadMore>

## Legacy

The following features are now considered legacy features. They should function normally but are no longer recommended and are in maintenance mode. They will see no future improvements and documentation will not be updated. These features will eventually be deprecated, and then removed entirely.
Expand Down