Skip to content

Conversation

@florian-lefebvre
Copy link
Member

@florian-lefebvre florian-lefebvre commented Nov 12, 2025

Changes

  • Closes Deprecate loader types generation from schema #14381
  • Goal is to get rid of zod-to-ts. It requires quite a few changes:
    • Removes loader schema function signature
    • Adds a new optional createSchema() property instead. It must return a zod schema as well as types (string). That means loaders authors can use zod-to-ts themselves to keep the previous behavior (migration path)
    • Loaders using a static schema will need to use satisfies Loader so we can infer types properly. It is kind of backward compatible with v5 loaders: it won't break but types will be any. It only affects loaders that specify a static top level schema
  • To be clear affected loaders are 3rd party ones that use dynamic schema generation (will break) OR 3rd party ones that use a schema without a user schema (types will be any)

Testing

Manual + updated

Docs

@florian-lefebvre florian-lefebvre added this to the v6.0.0 milestone Nov 12, 2025
@florian-lefebvre florian-lefebvre self-assigned this Nov 12, 2025
@changeset-bot
Copy link

changeset-bot bot commented Nov 12, 2025

🦋 Changeset detected

Latest commit: c0be1db

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added the pkg: astro Related to the core `astro` package (scope) label Nov 12, 2025
@github-actions github-actions bot added the pkg: example Related to an example package (scope) label Nov 13, 2025
@github-actions github-actions bot removed the pkg: example Related to an example package (scope) label Nov 13, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 13, 2025

📝 Changeset Validation Results

Changeset validation failed

Issues Found:

.changeset/deep-states-talk.md

Issue with: 'Adds a new defineContentLoader() type helper (Loader API) - (v6 upgrade guidance)'

❌ Change description lists 'Adds' which indicates a 'minor' change; please confirm if this should be 'Introduces' to indicate a major change impact.

💡 Ensure description properly reflects the impact of changes in relation to 'major' guidelines. For example: Introduces breaking functionality altering content loader configuration. Please verify for migration details.

General Errors:

  • Included upgrade guidance link leads to TODO placeholder section. Kindly confirm the final reference to critical migration documentation.

📖 See Astro's changeset guide for details.

@florian-lefebvre florian-lefebvre linked an issue Nov 13, 2025 that may be closed by this pull request
@florian-lefebvre
Copy link
Member Author

@delucis I'd like your review on this when you have time

@HiDeoo
Copy link
Member

HiDeoo commented Nov 17, 2025

  • To be clear affected loaders are 3rd party ones that use dynamic schema generation (will break) OR 3rd party ones that use a schema without a user schema (types will be any)

Small question purely based on reading the PR description so far.

The "3rd party ones that use a schema without a user schema (types will be any)" part represents 95% of my loaders and the majority of the ones I've worked with so I'm a bit anxious: am I understanding correctly that for a 3rd party loader that provides a top-level schema that is not a function:

  • Types will break and become any?
  • When migrating to defineContentLoader(), the loader will need to switch to getSchemaContext() and provide both the schema and the types as a string manually?

@florian-lefebvre
Copy link
Member Author

florian-lefebvre commented Nov 17, 2025

No for static schemas, types will be any until switching to defineContentLoader(), so we can infer the schema types properly. That's it. So to recap:

  • You're using a loader without schema: no change required but using defineContentLoader() is recommended
  • You're using a loader with a static schema: use defineContentLoader() otherwise types will be any. Note: if a user provides a schema then types will work
  • You're using a loader with a dynamic schema: breaking, switch to getSchemaContext(). Using defineContentLoader() is recommended

Copy link
Contributor

@ascorbic ascorbic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not really convinced about the value of having defineContentLoader. These sort of helpers are useful when a user is defining a config object and exporting it directly. However the pattern that we encourage for loader authors is to create a function that returns a loader. This is similar to how Vite provides defineConfig but not definePlugin. I don't really see the value of the helper vs a return type and generic. I'm concerned that the helper just makes it feel like more of a breaking change than it really is.

@florian-lefebvre
Copy link
Member Author

florian-lefebvre commented Nov 28, 2025

I don't really see the value of the helper vs a return type and generic.

One day we'll want to make another breaking change to types and we'll run in the same situation as today: it breaks until authors update their types. If we have this type helper, that means we can introduce breaking changes more easily in the future while making it easy for content authors. That's a big advantage IMO.

For people looking through this, here are the 2 options basically:

// OPTION 1
const schema = z.object({/* ... */})

export function myLoader(options): Loader<typeof schema> {
	return {
		name: '...',
		schema,
		async load() {}
	}
}

// OPTION 2
export functon myLoader(options) {
	return defineContentLoader({
		name: '...',
		schema: z.object({/* ... */}),
		async load() {}
	})
}

@matthewp
Copy link
Contributor

I think I side with @ascorbic here. If Astro is going to be a TypeScript project then I think we should embrace typescript features like function return types and satisfies. This is how we get proper type checking with API endpoints for example. I don't think creating a function wrapper for every type improves things enough to warrant the extra maintenance.

I'll acknowledge though that some people disagree and like these things and want their code to not have type annotations. Our job as a framework is to resolve these things in some way that maintains consistency, not to always make case-by-case decisions. So there probably needs to be a discussion outside of this PR on when define() wrappers are appropriate and when they are not. I can recall doing so in the past, but maybe its time to revisit and draw more clear lines.

Additionally, I think this PR is maybe overloaded. Can we not move defineContentLoader to another PR as to not block getSchemaContext?

@ascorbic
Copy link
Contributor

The other option is to tell users to do:

export function myLoader(options){
	return {
		name: '...',
		schema: z.object(),
		async load() {}
	} satisfies Loader
}

That fits with what we do for getStaticPaths etc

@florian-lefebvre
Copy link
Member Author

florian-lefebvre commented Dec 1, 2025

Alright I'll go with satisfies then, thanks for the feedback!

@florian-lefebvre florian-lefebvre changed the title feat: loader.getSchemaContext() feat: loader.createSchema() Dec 3, 2025
@florian-lefebvre florian-lefebvre marked this pull request as ready for review December 3, 2025 13:18
Copy link
Member

@sarah11918 sarah11918 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some suggestions from me for changeset/error message!

@florian-lefebvre florian-lefebvre merged commit d7889f7 into next Dec 4, 2025
22 checks passed
@florian-lefebvre florian-lefebvre deleted the feat/content-loader-get-schema-context branch December 4, 2025 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg: astro Related to the core `astro` package (scope)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deprecate loader types generation from schema

6 participants