diff --git a/astro.sidebar.ts b/astro.sidebar.ts
index ed4990f336ba0..e2017c9447d35 100644
--- a/astro.sidebar.ts
+++ b/astro.sidebar.ts
@@ -90,6 +90,7 @@ export const sidebar = [
group('guides.upgrade.major', {
collapsed: true,
items: [
+ 'guides/upgrade-to/v6',
'guides/upgrade-to/v5',
'guides/upgrade-to/v4',
'guides/upgrade-to/v3',
@@ -136,6 +137,7 @@ export const sidebar = [
'reference/content-loader-reference',
'reference/image-service-reference',
'reference/dev-toolbar-app-reference',
+ 'reference/session-driver-reference',
'reference/container-reference',
'reference/programmatic-reference',
],
@@ -143,17 +145,10 @@ export const sidebar = [
group('reference.experimental', {
items: [
'reference/experimental-flags',
- 'reference/experimental-flags/csp',
'reference/experimental-flags/fonts',
- 'reference/experimental-flags/live-content-collections',
'reference/experimental-flags/client-prerender',
'reference/experimental-flags/content-intellisense',
- 'reference/experimental-flags/preserve-scripts-order',
- 'reference/experimental-flags/heading-id-compat',
- 'reference/experimental-flags/static-import-meta-env',
'reference/experimental-flags/chrome-devtools-workspace',
- 'reference/experimental-flags/fail-on-prerender-conflict',
- 'reference/experimental-flags/svg-optimization',
],
}),
'reference/legacy-flags',
diff --git a/public/_headers b/public/_headers
index f56759cc14415..015d6749500c7 100644
--- a/public/_headers
+++ b/public/_headers
@@ -2,3 +2,7 @@
cache-control: max-age=31536000
cache-control: immutable
cache-control: public
+
+# TODO: Remove this before merging to main
+/*
+ x-robots-tag: no-index
diff --git a/src/content/docs/de/basics/project-structure.mdx b/src/content/docs/de/basics/project-structure.mdx
index 5027ff897bb6e..83a6698c66032 100644
--- a/src/content/docs/de/basics/project-structure.mdx
+++ b/src/content/docs/de/basics/project-structure.mdx
@@ -125,7 +125,7 @@ Eine Anleitung zur Erstellung einer neuen `package.json`-Datei für dein Projekt
Diese Datei wird von jeder Starter-Vorlage generiert und enthält Konfigurationsoptionen für dein Astro-Projekt. Hier kannst du die zu verwendenden Integrationen, Build-Optionen, Serveroptionen und mehr angeben.
-Astro unterstützt mehrere Dateiformate für seine JavaScript-Konfigurationsdatei: `astro.config.js`, `astro.config.mjs`, `astro.config.cjs` und `astro.config.ts`. Wir empfehlen, in den meisten Fällen `.mjs` oder `.ts` zu verwenden, wenn du TypeScript in deiner Konfigurationsdatei schreiben willst.
+Astro unterstützt mehrere Dateiformate für seine JavaScript-Konfigurationsdatei: `astro.config.js`, `astro.config.mjs` und `astro.config.ts`. Wir empfehlen, in den meisten Fällen `.mjs` oder `.ts` zu verwenden, wenn du TypeScript in deiner Konfigurationsdatei schreiben willst.
Das Laden von TypeScript-Konfigurationsdateien wird mit [`tsm`](https://github.com/lukeed/tsm) gehandhabt und berücksichtigt die `tsconfig`-Optionen deines Projekts.
diff --git a/src/content/docs/de/tutorial/6-islands/4.mdx b/src/content/docs/de/tutorial/6-islands/4.mdx
index 544c050e7d5bf..7c60d35154716 100644
--- a/src/content/docs/de/tutorial/6-islands/4.mdx
+++ b/src/content/docs/de/tutorial/6-islands/4.mdx
@@ -120,7 +120,6 @@ Aktualisiere Astro und alle Integrationen auf die neuesten Versionen, indem du i
```ts title="src/content.config.ts"
import { glob } from "astro/loaders";
import { defineCollection } from "astro:content";
- // Importiere Zod
import { z } from "astro/zod";
const blog = defineCollection({
@@ -150,7 +149,7 @@ Aktualisiere Astro und alle Integrationen auf die neuesten Versionen, indem du i
1. Erstelle eine neue Seitendatei `src/pages/posts/[...slug].astro`.
Markdown- und MDX-Dateien werden innerhalb einer Sammlung nicht mehr automatisch zu Seiten. Du musst daher eine Seite erstellen, die für die Ausgabe jedes einzelnen Blogbeitrags verantwortlich ist.
-2. Füge den folgenden Code ein, um deine Sammlung [abzufragen](/de/guides/content-collections/#querying-collections) und für jede generierte Seite die `slug` und den Seiteninhalt bereitzustellen:
+2. Füge den folgenden Code ein, um deine Sammlung [abzufragen](/de/guides/content-collections/#querying-build-time-collections) und für jede generierte Seite die `slug` und den Seiteninhalt bereitzustellen:
```astro title="src/pages/posts/[...slug].astro"
---
diff --git a/src/content/docs/en/basics/project-structure.mdx b/src/content/docs/en/basics/project-structure.mdx
index 8b2a0a00bcc4b..0963238cce2cd 100644
--- a/src/content/docs/en/basics/project-structure.mdx
+++ b/src/content/docs/en/basics/project-structure.mdx
@@ -124,7 +124,7 @@ For help creating a new `package.json` file for your project, check out the [man
This file is generated in every starter template and includes configuration options for your Astro project. Here you can specify integrations to use, build options, server options, and more.
-Astro supports several file formats for its JavaScript configuration file: `astro.config.js`, `astro.config.mjs`, `astro.config.cjs` and `astro.config.ts`. We recommend using `.mjs` in most cases or `.ts` if you want to write TypeScript in your config file.
+Astro supports several file formats for its JavaScript configuration file: `astro.config.js`, `astro.config.mjs` and `astro.config.ts`. We recommend using `.mjs` in most cases or `.ts` if you want to write TypeScript in your config file.
TypeScript config file loading is handled using [`tsm`](https://github.com/lukeed/tsm) and will respect your project's `tsconfig` options.
diff --git a/src/content/docs/en/getting-started.mdx b/src/content/docs/en/getting-started.mdx
index ec9c01835d6d2..9b70bb453fd03 100644
--- a/src/content/docs/en/getting-started.mdx
+++ b/src/content/docs/en/getting-started.mdx
@@ -5,6 +5,9 @@ i18nReady: true
tableOfContents: false
editUrl: false
next: false
+banner:
+ content: |
+ Astro v6 is here! Learn how to upgrade your site
hero:
title: Astro Docs
tagline: Guides, resources, and API references to help you build with Astro.
diff --git a/src/content/docs/en/guides/actions.mdx b/src/content/docs/en/guides/actions.mdx
index cfe4e8622fdab..1b930e30e2cf1 100644
--- a/src/content/docs/en/guides/actions.mdx
+++ b/src/content/docs/en/guides/actions.mdx
@@ -329,14 +329,14 @@ export const server = {
// Matches when the `type` field has the value `create`
type: z.literal('create'),
name: z.string(),
- email: z.string().email(),
+ email: z.email(),
}),
z.object({
// Matches when the `type` field has the value `update`
type: z.literal('update'),
id: z.number(),
name: z.string(),
- email: z.string().email(),
+ email: z.email(),
}),
]),
async handler(input) {
@@ -374,7 +374,7 @@ The following example shows a validated newsletter registration form that accept
```
-2. Define a `newsletter` action to handle the submitted form. Validate the `email` field using the `z.string().email()` validator, and the `terms` checkbox using `z.boolean()`:
+2. Define a `newsletter` action to handle the submitted form. Validate the `email` field using the `z.email()` validator, and the `terms` checkbox using `z.boolean()`:
```ts title="src/actions/index.ts" ins={5-12}
import { defineAction } from 'astro:actions';
@@ -384,7 +384,7 @@ The following example shows a validated newsletter registration form that accept
newsletter: defineAction({
accept: 'form',
input: z.object({
- email: z.string().email(),
+ email: z.email(),
terms: z.boolean(),
}),
handler: async ({ email, terms }) => { /* ... */ },
diff --git a/src/content/docs/en/guides/cms/cloudcannon.mdx b/src/content/docs/en/guides/cms/cloudcannon.mdx
index 0f4282a15da0d..e1b16866c96cb 100644
--- a/src/content/docs/en/guides/cms/cloudcannon.mdx
+++ b/src/content/docs/en/guides/cms/cloudcannon.mdx
@@ -141,7 +141,7 @@ The following example will create a new blog post from the CloudCannon Site Dash
## Rendering CloudCannon content
-Use Astro's Content Collections API to [query and display your posts and collections](/en/guides/content-collections/#querying-collections), just as you would in any Astro project.
+Use Astro's Content Collections API to [query and display your posts and collections](/en/guides/content-collections/#querying-build-time-collections), just as you would in any Astro project.
### Displaying a collection list
diff --git a/src/content/docs/en/guides/cms/keystatic.mdx b/src/content/docs/en/guides/cms/keystatic.mdx
index d8fdc1e12276a..6e94b455e57d4 100644
--- a/src/content/docs/en/guides/cms/keystatic.mdx
+++ b/src/content/docs/en/guides/cms/keystatic.mdx
@@ -183,7 +183,7 @@ Visit `http://127.0.0.1:4321/keystatic` in the browser to see the Keystatic Admi
## Rendering Keystatic content
-Use Astro's Content Collections API to [query and display your posts and collections](/en/guides/content-collections/#querying-collections), just as you would in any Astro project.
+[Query and display your posts and collections](/en/guides/content-collections/#querying-build-time-collections), just as you would in any Astro project.
### Displaying a collection list
diff --git a/src/content/docs/en/guides/configuring-astro.mdx b/src/content/docs/en/guides/configuring-astro.mdx
index ef4abace880a8..0e2f3b91d18f8 100644
--- a/src/content/docs/en/guides/configuring-astro.mdx
+++ b/src/content/docs/en/guides/configuring-astro.mdx
@@ -26,7 +26,7 @@ export default defineConfig({
It is only required if you have something to configure, but most projects will use this file. The `defineConfig()` helper provides automatic IntelliSense in your IDE and is where you will add all your configuration options to tell Astro how to build and render your project to HTML.
-We recommend using the default file format `.mjs` in most cases, or `.ts` if you want to write TypeScript in your config file. However, `astro.config.js` and `astro.config.cjs` are also supported.
+We recommend using the default file format `.mjs` in most cases, or `.ts` if you want to write TypeScript in your config file. However, `astro.config.js` is also supported.
Read Astro's [configuration reference](/en/reference/configuration-reference/) for a full overview of all supported configuration options.
diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx
index d85093421e967..c465ef84d4d91 100644
--- a/src/content/docs/en/guides/content-collections.mdx
+++ b/src/content/docs/en/guides/content-collections.mdx
@@ -3,6 +3,9 @@ title: Content collections
description: >-
Manage your content with type safety.
i18nReady: true
+tableOfContents:
+ minHeadingLevel: 2
+ maxHeadingLevel: 3
---
import { FileTree, CardGrid, LinkCard, Steps } from '@astrojs/starlight/components';
import Since from '~/components/Since.astro'
@@ -12,18 +15,13 @@ import ReadMore from "~/components/ReadMore.astro"
-**Content collections** are the best way to manage sets of content in any Astro project. Collections help to organize and query your documents, enable Intellisense and type checking in your editor, and provide automatic TypeScript type-safety for all of your content.
-Astro v5.0 introduced the Content Layer API for defining and querying content collections. This performant, scalable API provides built-in content loaders for your local collections. For remote content, you can use third-party and community-built loaders or create your own custom loader and pull in your data from any source.
+**Content collections** are the best way to manage sets of content in any Astro project: blog posts, product descriptions, character profiles, recipes, or any structured content. Collections help to organize and query your documents, enable Intellisense and type checking in your editor, and provide automatic TypeScript type-safety for all of your content.
-:::note
-Projects may continue using the legacy Content Collections API introduced in Astro v2.0. However, we encourage you to [update any existing collections](/en/guides/upgrade-to/v5/#legacy-v20-content-collections-api) when you are able.
-:::
+Astro provides performant, scalable APIs to load, query, and render content from anywhere: stored locally in your project, hosted remotely, or fetched live from frequently-updating sources.
## What are Content Collections?
-You can define a **collection** from a set of data that is structurally similar. This can be a directory of blog posts, a JSON file of product items, or any data that represents multiple items of the same shape.
-
-Collections stored locally in your project or on your filesystem can have entries of Markdown, MDX, Markdoc, YAML, TOML, or JSON files:
+A content collection is a set of related, structurally identical data. This data can be stored in one or several files locally (e.g. a folder of individual Markdown files of blog posts, a single JSON file of product descriptions) or fetched from remote sources such as a database, CMS, or API endpoint. Each member of the collection is called an entry.
- src/
@@ -35,32 +33,103 @@ Collections stored locally in your project or on your filesystem can have entrie
- authors.json a single file containing all collection entries
-With an appropriate collection loader, you can fetch remote data from any external source, such as a CMS, database, or headless payment system.
+Collections are defined by the location and shape of its entries and provide a convenient way to query and render your content and associated metadata. You can create a collection any time you have a group of related data or content, stored in the same location, that shares a common structure.
+
+[Two types of content collections](#types-of-collections) are available to allow you to work with data fetched either at build time or at request time. Both build-time collections and live updating collections use:
+
+- A required `loader` to retrieve your content and metadata from wherever it is stored and make it available to your project through content-focused APIs.
+- An optional collection `schema` that allows you to define the expected shape of each entry for type safety, autocomplete, and validation in your editor.
+
+Collections stored locally in your project or on your filesystem can use one of Astro's [provided build-time loaders](#build-time-collection-loaders) to fetch data from Markdown, MDX, Markdoc, YAML, TOML, or JSON files. Point Astro to the location of your content, define your data shape, and you're good to go with a blog or similarly content-heavy, mostly static site in no time!
+
+With [community-built loaders](https://astro.build/integrations/?search=&categories%5B%5D=loaders) or by building a [custom build-time collection loader](#custom-build-time-loaders) or [live loader](#creating-a-live-loader) yourself, you can fetch remote data from any external source, such as a CMS, database, or headless payment system, either at build time or live on demand.
+
+### Types of collections
+
+[Build-time content collections](#defining-build-time-content-collections) are updated at build time, and data is saved to a storage layer. This provides excellent performance for most content, but may not be suitable for frequently updating data sources requiring up-to-the-moment data freshness, such as live stock prices.
+
+For the best performance and scalability, use build-time content collections when one or more of these is true:
+
+- **Performance is critical** and you want to prerender data at build time.
+- **Your data is relatively static** (e.g., blog posts, documentation, product descriptions).
+- **You want to benefit from build-time optimization** and caching.
+- **You need to process MDX** or **perform image optimization**.
+- **Your data can be fetched once and reused** across multiple builds.
+
+:::tip[Quick start]
+See [the official Astro blog starter template](https://github.com/withastro/astro/tree/latest/examples/blog) to get up and running quickly with an example of using the [built-in `glob()` loader](#the-glob-loader) and [defining a schema](#defining-the-collection-schema) for a collection of local Markdown or MDX blog posts.
+:::
+
+[Live content collections](#live-content-collections) fetch their data at runtime rather than build time. This allows you to access frequently updated data from CMSs, APIs, databases, or other sources using a unified API, without needing to rebuild your site when the data changes. However, this can come at a performance cost since data is fetched at each request and returned directly with no data store persistence.
+
+Live content collections are designed for data that changes frequently and needs to be up-to-date when a page is requested. Consider using them when one or more of these is true:
+
+- **You need real-time information** (e.g. user-specific data, current stock levels).
+- **You want to avoid constant rebuilds** for content that changes often.
+- **Your data updates frequently** (e.g. up-to-the-minute product inventory, prices, availability).
+- **You need to pass dynamic filters** to your data source based on user input or request parameters.
+- **You're building preview functionality** for a CMS where editors need to see draft content immediately.
+
+Both kinds of collections can exist in the same project, so you can always choose the best type of collection for each individual data source. For example, a build-time collection can manage product descriptions, while a live collection can manage content inventory.
+
+Both types of collections use similar APIs (e.g. `getCollection()` and `getLiveCollection()`), so that working with collections will feel familiar no matter which one you choose, while still ensuring that you always know which type of collection you are working with.
+
+We suggest using build-time content collections whenever possible, and using live collections when your content needs updating in real time and the performance tradeoffs are acceptable. Additionally, live content collections have some limitations compared to build-time collections:
+
+- **No MDX support**: MDX cannot be rendered at runtime
+- **No image optimization**: Images cannot be processed at runtime
+- **Performance considerations**: Data is fetched on each request (unless cached)
+- **No data store persistence**: Data is not saved to the content layer data store
+
+### When to create a collection
+
+Define your data as a collection when:
+
+- You have multiple files or data to organize that share the same overall structure (e.g. a directory of blog posts written in Markdown which all have the same frontmatter properties).
+- You have existing content stored remotely, such as in a CMS, and want to take advantage of the collections helper functions instead of using `fetch()` or SDKs.
+- You need to fetch (tens of) thousands of related pieces of data at build time, and need a querying and caching method that handles at scale.
+
+Much of the benefit of using collections comes from:
+
+- Defining a common data shape to validate that an individual entry is "correct" or "complete", avoiding errors in production.
+- Content-focused APIs designed to make querying intuitive (e.g. `getCollection()` instead of `import.meta.glob()`) when importing and rendering content on your pages.
+- Access to both built-in loaders and access to the low-level [Content Loader API](/en/reference/content-loader-reference/) for retrieving your content. There are additionally several third-party and community-built loaders available, and you can build your own custom loader to fetch data from anywhere.
+- Performance and scalability. Build-time content collections data can be cached between builds and is suitable for tens of thousands of content entries.
+
+### When not to create a collection
+
+Collections provide excellent structure, safety, and organization when you have multiple pieces of content that must share the same properties.
+
+Collections may not be your solution if:
+
+- You have only one or a small number of different content pages. Consider [making individual page components](/en/basics/astro-pages/) such as `src/pages/about.astro` with your content directly instead.
+- You are displaying files that are not processed by Astro, such as PDFs. Place these static assets in the [`public/` directory](/en/basics/project-structure/#public) of your project instead.
+- Your data source has its own SDK/client library for imports that is incompatible with or does not offer a content loader, and you prefer to use it directly.
## TypeScript configuration for collections
-Content collections rely on TypeScript to provide Zod validation, Intellisense and type checking in your editor. If you are not extending one of Astro's `strict` or `strictest` TypeScript settings, you will need to ensure the following `compilerOptions` are set in your `tsconfig.json`:
+Content collections rely on TypeScript to provide Zod validation, Intellisense, and type checking in your editor. By default, Astro configures a [`strict` TypeScript template](/en/guides/typescript/#tsconfig-templates) when you create a new project using the `create astro` CLI command. Both of Astro's `strict` and `strictest` templates include the TypeScript settings your project needs for content collections.
-```json title="tsconfig.json" ins={5} {6}
+If you changed this setting to `base` because you are not writing TypeScript in your project, or are not using any of Astro's built-in templates, you will need to also add the following `compilerOptions` in your `tsconfig.json` to use content collections:
+
+```json title="tsconfig.json" ins={4-7}
{
- // Included with "astro/tsconfigs/strict" or "astro/tsconfigs/strictest"
"extends": "astro/tsconfigs/base",
+ // not needed for `strict` or `strictest`
"compilerOptions": {
- "strictNullChecks": true, // add if using `base` template
- "allowJs": true // required, and included with all Astro templates
+ "strictNullChecks": true,
+ "allowJs": true
}
}
```
-## Defining Collections
-
-Individual collections use `defineCollection()` to configure:
-- a `loader` for a data source (required)
-- a `schema` for type safety (optional, but highly recommended!)
+## Defining build-time content collections
-### The collection config file
+All of your build-time content collections are defined in a special `src/content.config.ts` file (`.js` and `.mjs` extensions are also supported) using `defineCollection()`, and then a single collections object is exported for use in your project.
-To define collections, you must create a `src/content.config.ts` file in your project (`.js` and `.mjs` extensions are also supported.) This is a special file that Astro will use to configure your content collections based on the following structure:
+Each individual collection configures:
+- [a build-time `loader`](#build-time-collection-loaders) for a data source (required)
+- [a build-time `schema`](#defining-the-collection-schema) for type safety (optional, but highly recommended!)
```ts title="src/content.config.ts"
// 1. Import utilities from `astro:content`
@@ -72,87 +141,151 @@ import { glob, file } from 'astro/loaders';
// 3. Import Zod
import { z } from 'astro/zod';
-// 4. Define your collection(s)
-const blog = defineCollection({ /* ... */ });
-const dogs = defineCollection({ /* ... */ });
+// 4. Define a `loader` and `schema` for each collection
+const blog = defineCollection({
+ loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
+ schema: z.object({
+ title: z.string(),
+ description: z.string(),
+ pubDate: z.coerce.date(),
+ updatedDate: z.coerce.date().optional(),
+ }),
+});
// 5. Export a single `collections` object to register your collection(s)
-export const collections = { blog, dogs };
+export const collections = { blog };
```
-### Defining the collection `loader`
+You can then use the dedicated `getCollection()` and `getEntry()` functions to [query your content collections data](#querying-build-time-collections) and render your content.
+
+You can choose to [generate page routes](#generating-routes-from-content) from your build-time collection entries at build time for an entirely static, prerendered site. Or, you can render your build-time collections on demand, choosing to delay building your page until it is first requested. This is useful when you have a large number of pages (e.g. thousands or tens of thousands) and want to delay building a static page until it is needed.
-The Content Layer API allows you to fetch your content (whether stored locally in your project or remotely) and uses a `loader` property to retrieve your data.
+## Build-time collection loaders
-#### Built-in loaders
+Astro provides two built-in loaders (`glob()` and `file()`) for fetching your local content at build time. Pass the location of your data in your project or on your filesystem, and these loaders will automatically handle your data and update the persistent data store content layer.
-Astro provides [two built-in loader functions](/en/reference/content-loader-reference/#built-in-loaders) (`glob()` and `file()`) for fetching your local content, as well as access to the API to construct your own loader and fetch remote data.
+To fetch remote data at build time, you can [build a custom loader](#custom-build-time-loaders) to retrieve your data and update the data store. Or, you can use any [third-party or community-published loader integration](https://astro.build/integrations/2/?search=&categories%5B%5D=loaders). Several already exist for popular content management systems as well as common data sources such as Obsidian vaults, GitHub repositories, or Bluesky posts.
-The [`glob()` loader](/en/reference/content-loader-reference/#glob-loader) creates entries from directories of Markdown, MDX, Markdoc, JSON, YAML, or TOML files from anywhere on the filesystem. It accepts a `pattern` of entry files to match using glob patterns supported by [micromatch](https://github.com/micromatch/micromatch#matching-features), and a base file path of where your files are located. Each entry's `id` will be automatically generated from its file name. Use this loader when you have one file per entry.
+### The `glob()` loader
-The [`file()` loader](/en/reference/content-loader-reference/#file-loader) creates multiple entries from a single local file. Each entry in the file must have a unique `id` key property. It accepts a `base` file path to your file and optionally a [`parser` function](#parser-function) for data files it cannot parse automatically. Use this loader when your data file can be parsed as an array of objects.
+The [`glob()` loader](/en/reference/content-loader-reference/#glob-loader) fetches entries from directories of Markdown, MDX, Markdoc, JSON, YAML, or TOML files from anywhere on the filesystem. If you store your content entries locally as separate files, such as a directory of blog posts, then the `glob()` loader is all you need to access your content.
-```ts title="src/content.config.ts" {6,10}
+This loader requires a `pattern` of entry files to match using glob patterns supported by [micromatch](https://github.com/micromatch/micromatch#matching-features), and a `base` file path of where your files are located. A unique `id` for each entry will be automatically generated from its file name, but you can [define custom IDs](#defining-custom-ids) if needed.
+
+```ts title="src/content.config.ts" {5}
import { defineCollection } from 'astro:content';
-import { glob, file } from 'astro/loaders'; // Not available with legacy API
-import { z } from 'astro/zod';
+import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
- schema: /* ... */
});
+
+export const collections = { blog };
+```
+
+#### Defining custom IDs
+
+When using the [`glob()` loader](#the-glob-loader) with Markdown, MDX, Markdoc, JSON, or TOML files, every content entry [`id`](/en/reference/modules/astro-content/#id) is automatically generated in an URL-friendly format based on the content filename. This unique `id` is used to query the entry directly from your collection. It is also useful when [creating new pages and URLs from your content](#generating-routes-from-content).
+
+You can override a single entry’s generated `id` by adding your own `slug` property to the file frontmatter or data object for JSON files. This is similar to the “permalink” feature of other web frameworks.
+
+```md title="src/blog/1.md" {3}
+---
+title: My Blog Post
+slug: my-custom-id/supports/slashes
+---
+Your blog post content here.
+```
+
+```json title="src/categories/1.json" {3}
+{
+ "title": "My Category",
+ "slug": "my-custom-id/supports/slashes",
+ "description": "Your category description here."
+}
+```
+
+You can also pass options to the `glob()` loader's [`generateID()` helper function](/en/reference/content-loader-reference/#generateid) when you define your build-time collection to adjust how `id`s are generated. For example, you may wish to revert the default behavior of converting uppercase letters to lowercase for each collection entry:
+
+```js title="src/content.config.ts"
+const authors = defineCollection({
+ /* Retrieve all JSON files in your authors directory while retaining
+ * uppercase letters in the ID. */
+ loader: glob({
+ pattern: '**/*.json',
+ base: "./src/data/authors",
+ generateId: ({ entry }) => entry.replace(/\.json$/, ''),
+ }),
+});
+```
+
+### The `file()` loader
+
+The [`file()` loader](/en/reference/content-loader-reference/#file-loader) fetches multiple entries from a single local file defined in your collection. The `file()` loader will automatically detect and parse (based on the file extension) a single array of objects from JSON and YAML files, and will treat each top-level table as an independent entry in TOML files.
+
+```ts title="src/content.config.ts" {5}
+import { defineCollection } from 'astro:content';
+import { file } from 'astro/loaders';
+
const dogs = defineCollection({
loader: file("src/data/dogs.json"),
- schema: /* ... */
});
-const probes = defineCollection({
- // `loader` can accept an array of multiple patterns as well as string patterns
- // Load all markdown files in the space-probes directory, except for those that start with "voyager-"
- loader: glob({ pattern: ['*.md', '!voyager-*'], base: 'src/data/space-probes' }),
- schema: z.object({
- name: z.string(),
- type: z.enum(['Space Probe', 'Mars Rover', 'Comet Lander']),
- launch_date: z.date(),
- status: z.enum(['Active', 'Inactive', 'Decommissioned']),
- destination: z.string(),
- operator: z.string(),
- notable_discoveries: z.array(z.string()),
- }),
-});
+export const collections = { dogs };
+```
+
+Each entry object in the file must have a unique `id` key property so that the entry can be identified and queried. Unlike the `glob()` loader, the `file()` loader will not automatically generate IDs for each entry.
-export const collections = { blog, dogs, probes };
+You can provide your entries as an array of objects with an `id` property, or in object form where the unique `id` is the key:
+
+```json title="src/data/dogs.json"
+// Specify an `id` property in each object of an array
+[
+ { "id": "poodle", "coat": "curly", "shedding": "low" },
+ { "id": "afghan", "coat": "short", "shedding": "low" }
+]
```
-##### `parser` function
+```json title="src/data/dogs.json"
+// Each key will be used as the `id`
+{
+ "poodle": { "coat": "curly", "shedding": "low" },
+ "afghan": { "coat": "silky", "shedding": "low" }
+}
+```
-The `file()` loader accepts a second argument that defines a `parser` function. This allows you to specify a custom parser (e.g. `csv-parse`) to create a collection from a file's contents.
+#### Parsing other data formats
-The `file()` loader will automatically detect and parse (based on their file extension) a single array of objects from JSON and YAML files, and will treat each top-level table as an independent entry in TOML files. Support for these file types is built-in, and there is no need for a `parser` unless you have a [nested JSON document](#nested-json-documents). To use other files, such as `.csv`, you will need to create a parser function.
+Support for parsing single JSON, YAML, and TOML files into collection entries withe the `file()` loader is built-in (unless you have a [nested JSON document](#nested-json-documents)). To load your collection from unsupported file types, such as `.csv`, you will need to create a [parser function](/en/reference/content-loader-reference/#parser). This function can be made async if required (e.g. to fetch files from the web, or if your parser is asyncronous).
-The following example shows importing a CSV parser, then loading a `cats` collection into your project by passing both a file path and `parser` function to the `file()` loader:
+The following example shows importing a third-party CSV parser then passing a custom `parser` function to the `file()` loader:
-```typescript title="src/content.config.ts"
+```typescript title="src/content.config.ts" {3} "parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true })"
import { defineCollection } from "astro:content";
import { file } from "astro/loaders";
import { parse as parseCsv } from "csv-parse/sync";
const cats = defineCollection({
- loader: file("src/data/cats.csv", { parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true })})
+ loader: file("src/data/cats.csv", {
+ parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true }),
+ }),
});
```
-###### Nested `.json` documents
+##### Nested `.json` documents
-The `parser` argument also allows you to load a single collection from a nested JSON document. For example, this JSON file contains multiple collections:
+The `parser()` argument can be used to load a single collection from a nested JSON document. For example, this JSON file contains multiple collections:
```json title="src/data/pets.json"
{"dogs": [{}], "cats": [{}]}
```
-You can separate these collections by passing a custom `parser` to the `file()` loader for each collection:
+You can separate these collections by passing a custom `parser()` function to the `file()` loader for each collection, using Astro's built-in JSON parsing:
```typescript title="src/content.config.ts"
+import { file } from "astro/loaders";
+import { defineCollection } from "astro:content";
+
const dogs = defineCollection({
loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).dogs })
});
@@ -161,48 +294,35 @@ const cats = defineCollection({
});
```
-#### Building a custom loader
-
-You can build a custom loader to fetch remote content from any data source, such as a CMS, a database, or an API endpoint.
-
-Using a loader to fetch your data will automatically create a collection from your remote data. This gives you all the benefits of local collections, such as collection-specific API helpers such as `getCollection()` and `render()` to query and display your data, as well as schema validation.
-
-:::tip
-Find community-built and third-party loaders in the [Astro integrations directory](https://astro.build/integrations/?search=&categories%5B%5D=loaders).
-:::
-
-##### Inline loaders
+### Custom build-time loaders
-You can define a loader inline, inside your collection, as an async function that returns an array of entries.
+You can [build a custom loader](/en/reference/content-loader-reference/#building-a-loader) using the Content Loader API to fetch remote content from any data source, such as a CMS, a database, or an API endpoint.
-This is useful for loaders that don't need to manually control how the data is loaded and stored. Whenever the loader is called, it will clear the store and reload all the entries.
+Then you can import and define your custom loader in your collections config, passing any required values:
```ts title="src/content.config.ts"
-const countries = defineCollection({
- loader: async () => {
- const response = await fetch("https://restcountries.com/v3.1/all");
- const data = await response.json();
- // Must return an array of entries with an id property, or an object with IDs as keys and entries as values
- return data.map((country) => ({
- id: country.cca3,
- ...country,
- }));
- },
- schema: /* ... */
+import { defineCollection } from 'astro:content';
+import { myLoader } from './loader.ts';
+
+const blog = defineCollection({
+ loader: myLoader({
+ url: "https://api.example.com/posts",
+ apiKey: "my-secret",
+ }),
});
```
-The returned entries are stored in the collection and can be queried using the `getCollection()` and `getEntry()` functions.
-
-##### Loader objects
+:::tip
+Find community-built and third-party loaders in the [Astro integrations directory](https://astro.build/integrations/?search=&categories%5B%5D=loaders).
+:::
-For more control over the loading process, you can use the Content Loader API to create a loader object. For example, with access to the `load` method directly, you can create a loader that allows entries to be updated incrementally or clears the store only when necessary.
+Using a custom loader to fetch your data will automatically create a collection from your remote data. This gives you all the benefits of local collections, including collection-specific API helpers such as `getCollection()` and `render()` to [query and display your data](#querying-build-time-collections), as well as schema validation.
-Similar to creating an Astro integration or Vite plugin, you can [distribute your loader as an NPM package](/en/reference/publish-to-npm/) that others can use in their projects.
+Similar to creating an Astro integration or Vite plugin, you can [distribute your loader as an npm package](/en/reference/publish-to-npm/) that others can use in their projects.
-See the full [Content Loader API](/en/reference/content-loader-reference/) and examples of how to build your own loader.
+See the full [Content Loader API](/en/reference/content-loader-reference/) for examples of how to build your own loader.
-### Defining the collection schema
+## Defining the collection schema
Schemas enforce consistent frontmatter or entry data within a collection through Zod validation. A schema **guarantees** that this data exists in a predictable form when you need to reference or query it. If any file violates its collection schema, Astro will provide a helpful error to let you know.
@@ -212,12 +332,12 @@ Schemas also power Astro's automatic TypeScript typings for your content. When y
In order for Astro to recognize a new or updated schema, you may need to restart the dev server or [sync the content layer](/en/reference/cli-reference/#astro-dev) (s + enter) to define the `astro:content` module.
:::
-Every frontmatter or data property of your collection entries must be defined using a [Zod data type](/en/reference/modules/astro-zod/#common-data-type-validators):
+Providing a `schema` is optional, but highly recommended! If you choose to use a schema, then every frontmatter or data property of your collection entries must be defined using a [Zod data type](/en/reference/modules/astro-zod/#common-data-type-validators):
```ts title="src/content.config.ts" {7-12,16-20}
import { defineCollection } from 'astro:content';
-import { glob, file } from 'astro/loaders';
import { z } from 'astro/zod';
+import { glob, file } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
@@ -240,23 +360,23 @@ const dogs = defineCollection({
export const collections = { blog, dogs };
```
-#### Defining datatypes with Zod
+### Defining datatypes with Zod
-Astro uses [Zod](https://github.com/colinhacks/zod) to power its content schemas. With Zod, Astro is able to validate every file's data within a collection *and* provide automatic TypeScript types when you go to query content from inside your project.
+Astro uses [Zod](https://github.com/colinhacks/zod) to power its content schemas. With Zod, Astro is able to validate every file's data within a collection *and* provide automatic TypeScript types when you query content from inside your project.
-To use Zod in Astro, import the `z` utility from `"astro/zod"`. This is a re-export of the Zod library, and it supports all of the features of Zod.
+To use Zod in Astro, import the `z` utility from `"astro/zod"`. This is a re-export of the Zod library, and it supports all of the features of Zod 4.
See the [`z` utility reference](/en/reference/modules/astro-zod/) for a cheatsheet of common datatypes and to learn how Zod works and what features are available.
-##### Zod schema methods
+#### Zod schema methods
All [Zod schema methods](/en/reference/modules/astro-zod/#using-zod-methods) (e.g. `.parse()`, `.transform()`) are available, with some limitations. Notably, performing custom validation checks on images using `image().refine()` is unsupported.
-#### Defining collection references
+### Defining collection references
Collection entries can also "reference" other related entries.
-With the [`reference()` function](/en/reference/modules/astro-content/#reference) from the Collections API, you can define a property in a collection schema as an entry from another collection. For example, you can require that every `space-shuttle` entry includes a `pilot` property which uses the `pilot` collection's own schema for type checking, autocomplete, and validation.
+With the [`reference()` function](/en/reference/modules/astro-content/#reference), you can define a property in a collection schema as an entry from another collection. For example, you can require that every `space-shuttle` entry includes a `pilot` property which uses the `pilot` collection's own schema for type checking, autocomplete, and validation.
A common example is a blog post that references reusable author profiles stored as JSON, or related post URLs stored in the same collection:
@@ -266,21 +386,21 @@ import { glob } from 'astro/loaders';
import { z } from 'astro/zod';
const blog = defineCollection({
- loader: glob({ pattern: '**/[^_]*.md', base: "./src/data/blog" }),
+ loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
schema: z.object({
title: z.string(),
// Reference a single author from the `authors` collection by `id`
author: reference('authors'),
- // Reference an array of related posts from the `blog` collection by `slug`
+ // Reference an array of related posts from the `blog` collection by `id`
relatedPosts: z.array(reference('blog')),
})
});
const authors = defineCollection({
- loader: glob({ pattern: '**/[^_]*.json', base: "./src/data/authors" }),
+ loader: glob({ pattern: '**/*.json', base: "./src/data/authors" }),
schema: z.object({
name: z.string(),
- portfolio: z.string().url(),
+ portfolio: z.url(),
})
});
@@ -301,38 +421,17 @@ relatedPosts:
These references will be transformed into objects containing a `collection` key and an `id` key, allowing you to easily [query them in your templates](/en/guides/content-collections/#accessing-referenced-data).
-### Defining custom IDs
-
-When using the `glob()` loader with Markdown, MDX, Markdoc, or JSON files, every content entry [`id`](/en/reference/modules/astro-content/#id) is automatically generated in an URL-friendly format based on the content filename. The `id` is used to query the entry directly from your collection. It is also useful when creating new pages and URLs from your content.
-
-You can override an entry’s generated `id` by adding your own `slug` property to the file frontmatter or data object for JSON files. This is similar to the “permalink” feature of other web frameworks.
-
-```md title="src/blog/1.md" {3}
----
-title: My Blog Post
-slug: my-custom-id/supports/slashes
----
-Your blog post content here.
-```
-
-```json title="src/categories/1.json" {3}
-{
- "title": "My Category",
- "slug": "my-custom-id/supports/slashes",
- "description": "Your category description here."
-}
-```
-
-## Querying Collections
+## Querying build-time collections
-Astro provides helper functions to query a collection and return one (or more) content entries.
+Astro provides helper functions to query a build-time collection and return one or more content entries.
- [`getCollection()`](/en/reference/modules/astro-content/#getcollection) fetches an entire collection and returns an array of entries.
- [`getEntry()`](/en/reference/modules/astro-content/#getentry) fetches a single entry from a collection.
These return entries with a unique `id`, a `data` object with all defined properties, and will also return a `body` containing the raw, uncompiled body of a Markdown, MDX, or Markdoc document.
-```js
+```astro title="src/pages/index.astro"
+---
import { getCollection, getEntry } from 'astro:content';
// Get all entries from a collection.
@@ -342,8 +441,7 @@ const allBlogPosts = await getCollection('blog');
// Get a single entry from a collection.
// Requires the name of the collection and `id`
const poodleData = await getEntry('dogs', 'poodle');
-
-
+---
```
The sort order of generated collections is non-deterministic and platform-dependent. This means that if you are calling `getCollection()` and need your entries returned in a specific order (e.g. blog posts sorted by date), you must sort the collection entries yourself:
@@ -362,7 +460,9 @@ const posts = (await getCollection('blog')).sort(
### Using content in Astro templates
-After querying your collections, you can access each entry's content directly inside of your Astro component template. For example, you can create a list of links to your blog posts, displaying information from your entry's frontmatter using the `data` property.
+After querying your collections, you can access each entry's content and metadata directly inside of your Astro component template.
+
+For example, you can create a list of links to your blog posts, displaying information from your entry's frontmatter using the `data` property:
```astro title="src/pages/index.astro"
@@ -377,21 +477,20 @@ const posts = await getCollection('blog');
))}
```
-#### Rendering body content
-Once queried, you can render Markdown and MDX entries to HTML using the [`render()`](/en/reference/modules/astro-content/#render) function property. Calling this function gives you access to rendered HTML content, including both a ` ` component and a list of all rendered headings.
+### Rendering body content
-```astro title="src/pages/blog/post-1.astro" {5,8}
+Once queried, you can render Markdown and MDX entries to HTML using the [`render()`](/en/reference/modules/astro-content/#render) function from `astro:content`. Calling this function gives you access to rendered HTML content, including both a ` ` component and a list of all rendered headings.
+
+```astro title="src/pages/blog/post-1.astro" {2,9}
---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('blog', 'post-1');
-if (!entry) {
- // Handle Error, for example:
- throw new Error('Could not find blog post 1');
-}
-const { Content, headings } = await render(entry);
+
+const { Content } = await render(entry);
---
+{entry.data.title}
Published on: {entry.data.published.toDateString()}
```
@@ -422,48 +521,60 @@ const { post } = Astro.props;
You can use this to filter by any content criteria you like. For example, you can filter by properties like `draft` to prevent any draft blog posts from publishing to your blog:
-```js
+```astro title="src/pages/blog.astro"
+---
// Example: Filter out content entries with `draft: true`
import { getCollection } from 'astro:content';
const publishedBlogEntries = await getCollection('blog', ({ data }) => {
return data.draft !== true;
});
+---
```
You can also create draft pages that are available when running the dev server, but not built in production:
-```js
+```astro title="src/pages/blog.astro"
+---
// Example: Filter out content entries with `draft: true` only when building for production
import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog', ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true;
});
+---
```
The filter argument also supports filtering by nested directories within a collection. Since the `id` includes the full nested path, you can filter by the start of each `id` to only return items from a specific nested directory:
-```js
+```astro title="src/pages/blog.astro"
+---
// Example: Filter entries by sub-directory in the collection
import { getCollection } from 'astro:content';
const englishDocsEntries = await getCollection('docs', ({ id }) => {
return id.startsWith('en/');
});
+---
```
### Accessing referenced data
-Any [references defined in your schema](/en/guides/content-collections/#defining-collection-references) must be queried separately after first querying your collection entry. Since the [`reference()` function](/en/reference/modules/astro-content/#reference) transforms a reference to an object with `collection` and `id` as keys, you can use the `getEntry()` function to return a single referenced item, or `getEntries()` to retrieve multiple referenced entries from the returned `data` object.
+To access [references defined in your schema](/en/guides/content-collections/#defining-collection-references), first query your collection entry. Your references will be available on the returned `data` object. (e.g. `entry.data.author` and `entry.data.relatedPosts`)
-```astro title="src/pages/blog/welcome.astro"
+Then, you can use the `getEntry()` function again (or `getEntries()` to retrieve multiple referenced entries) by passing those returned values. The `reference()` function in your schema transforms those values into one or more `collection` and `id` objects as a convenient way to query this related data.
+
+
+```astro title="src/pages/blog/adventures-in-space.astro"
---
import { getEntry, getEntries } from 'astro:content';
-const blogPost = await getEntry('blog', 'welcome');
+// First, query a blog post
+const blogPost = await getEntry('blog', 'Adventures in Space');
-// Resolve a singular reference (e.g. `{collection: "authors", id: "ben-holmes"}`)
+// Retrieve a single reference item: the blog post's author
+// Equivalent to querying `{collection: "authors", id: "ben-holmes"}`
const author = await getEntry(blogPost.data.author);
-// Resolve an array of references
-// (e.g. `[{collection: "blog", id: "about-me"}, {collection: "blog", id: "my-year-in-review"}]`)
+
+// Retrieve an array of referenced items: all the related posts
+// Equivalent to querying `[{collection: "blog", id: "visiting-mars"}, {collection: "blog", id: "leaving-earth-for-the-first-time"}]`
const relatedPosts = await getEntries(blogPost.data.relatedPosts);
---
@@ -480,17 +591,17 @@ const relatedPosts = await getEntries(blogPost.data.relatedPosts);
## Generating Routes from Content
-Content collections are stored outside of the `src/pages/` directory. This means that no pages or routes are generated for your collection items by default.
+Content collections are stored outside of the `src/pages/` directory. This means that no pages or routes are generated for your collection items by default by Astro's [file-based routing](/en/guides/routing/).
-You will need to manually create a new [dynamic route](/en/guides/routing/#dynamic-routes) if you want to generate HTML pages for each of your collection entries, such as individual blog posts. Your dynamic route will map the incoming request param (e.g. `Astro.params.slug` in `src/pages/blog/[...slug].astro`) to fetch the correct entry for each page.
+You will need to manually create a new [dynamic route](/en/guides/routing/#dynamic-routes) if you want to generate HTML pages for each of your collection entries, such as individual blog posts. Your dynamic route will map the incoming request param (e.g. `Astro.params.id` in `src/pages/blog/[...id].astro`) to fetch the correct entry for each page.
The exact method for generating routes will depend on whether your pages are prerendered (default) or rendered on demand by a server.
### Building for static output (default)
-If you are building a static website (Astro's default behavior), use the [`getStaticPaths()`](/en/reference/routing-reference/#getstaticpaths) function to create multiple pages from a single page component (e.g. `src/pages/[slug]`) during your build.
+If you are building a static website (Astro's default behavior) with build-time collections, use the [`getStaticPaths()`](/en/reference/routing-reference/#getstaticpaths) function to create multiple pages from a single page component (e.g. `src/pages/[id].astro`) during your build.
-Call `getCollection()` inside of `getStaticPaths()` to have your collection data available for building static routes. Then, create the individual URL paths using the `id` property of each content entry. Each page is passed the entire collection entry as a prop for [use in your page template](#using-content-in-astro-templates).
+Call `getCollection()` inside of `getStaticPaths()` to have your collection data available for building static routes. Then, create the individual URL paths using the `id` property of each content entry. Each page receives the entire collection entry as a prop for [use in your page template](#using-content-in-astro-templates).
```astro title="src/pages/posts/[id].astro" "{ id: post.id }" "{ post }"
---
@@ -514,28 +625,37 @@ const { Content } = await render(post);
This will generate a page route for every entry in the `blog` collection. For example, an entry at `src/blog/hello-world.md` will have an `id` of `hello-world`, and therefore its final URL will be `/posts/hello-world/`.
:::note
-If your custom slugs contain the `/` character to produce URLs with multiple path segments, you must use a [rest parameter (e.g. `[...slug]`)](/en/guides/routing/#rest-parameters) in the `.astro` filename for this dynamic routing page.
+If your custom slugs contain the `/` character to produce URLs with multiple path segments, you must use a [rest parameter (e.g. `[...id]`)](/en/guides/routing/#rest-parameters) in the `.astro` filename for this dynamic routing page.
:::
-### Building for server output (SSR)
+### Building routes on demand at request time
+
+With an adapter installed for [on-demand rendering](/en/guides/on-demand-rendering/), you can generate your dynamic page routes at request time. First, examine the request (using `Astro.request` or `Astro.params`) to find the slug on demand, and then fetch it using one of Astro's content collection helper functions:
-If you are building a dynamic website (using Astro's SSR support), you are not expected to generate any paths ahead of time during the build. Instead, your page should examine the request (using `Astro.request` or `Astro.params`) to find the `slug` on-demand, and then fetch it using [`getEntry()`](/en/reference/modules/astro-content/#getentry).
+- [`getEntry()`](/en/reference/modules/astro-content/#getentry) for build-time collection pages that are generated once, upon first request.
+- [`getLiveEntry()`](/en/reference/modules/astro-content/#getentry) for live collection pages where data is (re)fetched at each request time.
```astro title="src/pages/posts/[id].astro"
---
+export const prerender = false; // Not needed in 'server' mode
+
import { getEntry, render } from "astro:content";
+
// 1. Get the slug from the incoming server request
const { id } = Astro.params;
if (id === undefined) {
return Astro.redirect("/404");
}
+
// 2. Query for the entry directly using the request slug
const post = await getEntry("blog", id);
+
// 3. Redirect if the entry does not exist
if (post === undefined) {
return Astro.redirect("/404");
}
+
// 4. Render the entry to HTML in the template
const { Content } = await render(post);
---
@@ -544,10 +664,210 @@ const { Content } = await render(post);
```
:::tip
-Explore the `src/pages/` folder of the [blog tutorial demo code on GitHub](https://github.com/withastro/blog-tutorial-demo/tree/content-collections/src/pages) to see full examples of creating pages from your collections for blog features like a list of blog posts, tags pages, and more!
+Explore the `src/pages/` folder of the [blog tutorial demo code on GitHub](https://github.com/withastro/blog-tutorial-demo/tree/content-collections/src/pages) to see full examples of creating dynamic pages from your collections for blog features like a list of blog posts, tags pages, and more!
:::
-## Collection JSON Schemas
+## Live content collections
+
+Live collections use a different API than build-time content collections, although the configuration and helper functions are designed to feel familiar.
+
+Key differences include:
+
+1. **Execution time**: Run at request time instead of build time
+2. **Configuration file**: Use `src/live.config.ts` instead of `src/content.config.ts`
+3. **Collection definition**: Use `defineLiveCollection()` instead of `defineCollection()`
+4. **Loader API**: Implement `loadCollection` and `loadEntry` methods instead of the `load` method
+5. **Data return**: Return data directly instead of storing in the data store
+6. **User-facing functions**: Use `getLiveCollection()`/`getLiveEntry()` instead of `getCollection()`/`getEntry()`
+
+Additionally, you must have an adapter configured for [on-demand rendering](/en/guides/on-demand-rendering/) of live collection data.
+
+Define your live collections in the special file `src/live.config.ts` (separate from your `src/content.config.ts` for build-time collections, if you have one).
+
+Each individual collection configures:
+- a [live `loader`](#creating-a-live-loader) for your data source, and optionally for type safety (required)
+- a [live collection `schema`](#using-zod-schemas-with-live-collections) for type safety (optional)
+
+Unlike for build-time collections, there are no built-in live loaders available. You will need to [create a custom live loader](#creating-a-live-loader) for your specific data source or find a third-party loader to pass to your live collection's `loader` property.
+
+You can optionally [include type safety in your live loaders](/en/reference/content-loader-reference/#the-liveloader-object). Therefore, [defining a Zod `schema`](#using-zod-schemas-with-live-collections) for live collections is optional. However, if you provide one, it will take precedence over the live loader's types.
+
+```ts title="src/live.config.ts"
+// Define live collections for accessing real-time data
+import { defineLiveCollection } from 'astro:content';
+import { storeLoader } from '@mystore/astro-loader';
+
+const products = defineLiveCollection({
+ loader: storeLoader({
+ apiKey: process.env.STORE_API_KEY,
+ endpoint: 'https://api.mystore.com/v1',
+ }),
+});
+
+// Export a single `collections` object to register your collection(s)
+export const collections = { products };
+```
+
+You can then use the dedicated `getLiveCollection()` and `getLiveEntry()` functions to [access your live data](#accessing-live-data) and render your content.
+
+You can [generate page routes](#generating-routes-from-content) from your live collection entries on demand, fetching your data fresh at runtime upon each request without needing a rebuild of your site like [build-time collections](#defining-build-time-content-collections) do. This is useful when accessing live, up-to-the-moment data is more important than having your content available in a performant data storage layer that persists between site builds.
+
+### Creating a live loader
+
+You can build a custom [live loader](/en/reference/content-loader-reference/#live-loaders) using the Live Loader API to fetch remote content fresh upon request from any data source, such as a CMS, a database or an API endpoint. You will have to tell your live loader how to fetch and return content entries from your desired data source, as well as provide error handling for unsuccessful data requests.
+
+Using a live loader to fetch your data will automatically create a collection from your remote data. This gives you all the benefits of Astro's content collections, including collection-specific API helpers such as `getLiveCollection()` and `render()` to [query and display your data](#querying-build-time-collections), as well as helpful error handling.
+
+:::tip
+Find community-built and third-party live loaders in the [Astro integrations directory](https://astro.build/integrations/?search=&categories%5B%5D=loaders).
+:::
+
+See the basics of [building a live loader](/en/reference/content-loader-reference/#building-a-live-loader) using the Live Loader API
+
+### Using Zod schemas with live collections
+
+You can use Zod schemas with live collections to validate and transform data at runtime. This Zod validation works the same way as [schemas for build-time collections](#defining-the-collection-schema).
+
+When you define a schema for a live collection, it takes precedence over [the live loader's types](/en/reference/content-loader-reference/#the-liveloader-object) when you query the collection:
+
+```ts title="src/live.config.ts"
+import { z, defineLiveCollection } from 'astro:content';
+import { apiLoader } from './loaders/api-loader';
+
+const products = defineLiveCollection({
+ loader: apiLoader({ endpoint: process.env.API_URL }),
+ schema: z
+ .object({
+ id: z.string(),
+ name: z.string(),
+ price: z.number(),
+ // Transform the API's category format
+ category: z.string().transform((str) => str.toLowerCase().replace(/\s+/g, '-')),
+ // Coerce the date to a Date object
+ createdAt: z.coerce.date(),
+ })
+ .transform((data) => ({
+ ...data,
+ // Add a formatted price field
+ displayPrice: `$${data.price.toFixed(2)}`,
+ })),
+});
+
+export const collections = { products };
+```
+
+When using Zod schemas with live collections, validation errors are automatically caught and returned as `AstroError` objects:
+
+```astro title="src/pages/store/index.astro"
+---
+export const prerender = false; // Not needed in 'server' mode
+
+import { LiveCollectionValidationError } from 'astro/content/runtime';
+import { getLiveEntry } from 'astro:content';
+
+const { entry, error } = await getLiveEntry('products', '123');
+
+// You can handle validation errors specifically
+if (LiveCollectionValidationError.is(error)) {
+ console.error(error.message);
+ return Astro.rewrite('/500');
+}
+
+// TypeScript knows entry.data matches your Zod schema, not the loader's type
+console.log(entry?.data.displayPrice); // e.g., "$29.99"
+---
+```
+
+See [Zod's README](https://github.com/colinhacks/zod) for complete documentation on how Zod works and what features are available.
+
+
+### Accessing live data
+
+Astro provides live collection helper functions to access live data on each request and return one (or more) content entries. These can be used similarly to their [build-time collection counterparts](#querying-build-time-collections).
+
+- [`getLiveCollection()`](/en/reference/modules/astro-content/#getlivecollection) fetches an entire collection and returns an array of entries.
+- [`getLiveEntry()`](/en/reference/modules/astro-content/#getliveentry) fetches a single entry from a collection.
+
+These return entries with a unique `id`, and `data` object with all defined properties from the live loader. When using third-party or community loaders distributed as npm packages, check their own documentation for the expected shape of data returned.
+
+You can use these functions to access your live data, passing the name of the collection and optionally filtering conditions.
+
+```astro title="src/pages/store/[slug].astro"
+---
+export const prerender = false; // Not needed in 'server' mode
+
+import { getLiveCollection, getLiveEntry } from 'astro:content';
+
+// Use loader-specific filters
+const { entries: draftArticles } = await getLiveCollection('articles', {
+ status: 'draft',
+ author: 'john-doe',
+});
+
+// Get a specific product by ID
+const { entry: product } = await getLiveEntry('products', Astro.params.slug);
+---
+```
+
+#### Rendering content
+
+If your live loader [returns a `rendered` property](/en/reference/content-loader-reference/#rendered-1), you can use [the `render()` function and ` ` component](#rendering-body-content) to render your content directly in your pages, using the same method as build-time collections.
+
+You also have access to any [error returned by the live loader](/en/reference/content-loader-reference/#error-handling-in-live-loaders), for example, to rewrite to a 404 page when content cannot be displayed:
+
+```astro title="src/pages/store/[id].astro" "render(entry)" " "
+---
+export const prerender = false; // Not needed in 'server' mode
+
+import { getLiveEntry, render } from 'astro:content';
+const { entry, error } = await getLiveEntry('articles', Astro.params.id);
+if (error) {
+ return Astro.rewrite('/404');
+}
+
+const { Content } = await render(entry);
+---
+
+{entry.data.title}
+
+```
+
+#### Error handling
+
+Live loaders can fail due to network issues, API errors, or validation problems. The API is designed to make error handling explicit.
+
+When you call `getLiveCollection()` or `getLiveEntry()`, the error will be one of:
+
+- The error type defined by the loader (if it returned an error)
+- A `LiveEntryNotFoundError` if the entry was not found
+- A `LiveCollectionValidationError` if the collection data does not match the expected schema
+- A `LiveCollectionCacheHintError` if the cache hint is invalid
+- A `LiveCollectionError` for other errors, such as uncaught errors thrown in the loader
+
+You can use `instanceof` to check the type of an error at runtime:
+
+```astro title="src/pages/store/[id].astro" "LiveEntryNotFoundError.is(error)"
+---
+export const prerender = false; // Not needed in 'server' mode
+
+import { LiveEntryNotFoundError } from 'astro/content/runtime';
+import { getLiveEntry } from 'astro:content';
+
+const { entry, error } = await getLiveEntry('products', Astro.params.id);
+
+if (error) {
+ if (error instanceof LiveEntryNotFoundError) {
+ console.error(`Product not found: ${error.message}`);
+ Astro.response.status = 404;
+ } else {
+ console.error(`Error loading product: ${error.message}`);
+ return Astro.redirect('/500');
+ }
+}
+---
+```
+
+## Using JSON Schema files in your editor
@@ -556,7 +876,7 @@ Astro auto-generates [JSON Schema](https://json-schema.org/) files for collectio
A JSON Schema file is generated for each collection in your project and output to the `.astro/collections/` directory.
For example, if you have two collections, one named `authors` and another named `posts`, Astro will generate `.astro/collections/authors.schema.json` and `.astro/collections/posts.schema.json`.
-### Use JSON Schemas in JSON files
+Use JSON Schemas in JSON files
You can manually point to an Astro-generated schema by setting the `$schema` field in your JSON file.
The value should be a relative file path from the data file to the schema.
@@ -570,9 +890,9 @@ In the following example, a data file in `src/data/authors/` uses the schema gen
}
```
-#### Use a schema for a group of JSON files in VS Code
+Use a schema for a group of JSON files in VS Code
-In VS Code, you can configure a schema to apply for all files in a collection using the [`json.schemas` setting](https://code.visualstudio.com/docs/languages/json#_json-schemas-and-settings).
+In VS Code, you can configure a schema to apply to all files in a collection using the [`json.schemas` setting](https://code.visualstudio.com/docs/languages/json#_json-schemas-and-settings).
In the following example, all files in the `src/data/authors/` directory will use the schema generated for the `authors` collection:
```json
@@ -586,7 +906,7 @@ In the following example, all files in the `src/data/authors/` directory will us
}
```
-### Use schemas in YAML files in VS Code
+Use schemas in YAML files in VS Code
In VS Code, you can add support for using JSON schemas in YAML files using the [Red Hat YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) extension.
With this extension installed, you can reference a schema in a YAML file using a special comment syntax:
@@ -599,9 +919,9 @@ skills:
- Starlight
```
-#### Use schemas for a group of YAML files in VS Code
+Use schemas for a group of YAML files in VS Code
-With the Red Hat YAML extension, you can configure a schema to apply for all YAML files in a collection using the `yaml.schemas` setting.
+With the Red Hat YAML extension, you can configure a schema to apply to all YAML files in a collection using the `yaml.schemas` setting.
In the following example, all YAML files in the `src/data/authors/` directory will use the schema generated for the `authors` collection:
```json
@@ -613,31 +933,3 @@ In the following example, all YAML files in the `src/data/authors/` directory wi
```
See [“Associating schemas”](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml#associating-schemas) in the Red Hat YAML extension documentation for more details.
-
-## When to create a collection
-
-You can [create a collection](#defining-collections) any time you have a group of related data or content that shares a common structure.
-
-Much of the benefit of using collections comes from:
-
-- Defining a common data shape to validate that an individual entry is "correct" or "complete", avoiding errors in production.
-- Content-focused APIs designed to make querying intuitive (e.g. `getCollection()` instead of `import.meta.glob()`) when importing and rendering content on your pages.
-- A [Content Loader API](/en/reference/content-loader-reference/) for retrieving your content that provides both built-in loaders and access to the low-level API. There are several third-party and community-built loaders available, and you can build your own custom loader to fetch data from anywhere.
-- Performance and scalability. The Content Layer API allows data to be cached between builds and is suitable for tens of thousands of content entries.
-
-[Define your data](#defining-collections) as a collection when:
-
-- You have multiple files or data to organize that share the same overall structure (e.g. blog posts written in Markdown which all have the same frontmatter properties).
-- You have existing content stored remotely, such as in a CMS, and want to take advantage of the collections helper functions and Content Layer API instead of using `fetch()` or SDKs.
-- You need to fetch (tens of) thousands of related pieces of data, and need a querying and caching method that handles at scale.
-
-### When not to create a collection
-
-Collections provide excellent structure, safety, and organization when you have **multiple pieces of content that must share the same properties**.
-
-Collections **may not be your solution** if:
-
-- You have only one or a small number of different pages. Consider [making individual page components](/en/basics/astro-pages/) such as `src/pages/about.astro` with your content directly instead.
-- You are displaying files that are not processed by Astro, such as PDFs. Place these static assets in the [`public/` directory](/en/basics/project-structure/#public) of your project instead.
-- Your data source has its own SDK/client library for imports that is incompatible with or does not offer a content loader and you prefer to use it directly.
-- You are using APIs that need to be updated in real time. Content collections are only updated at build time, so if you need live data, use other methods of [importing files](/en/guides/imports/#import-statements) or [fetching data](/en/guides/data-fetching/) with [on-demand rendering](/en/guides/on-demand-rendering/).
diff --git a/src/content/docs/en/guides/deploy/microsoft-azure.mdx b/src/content/docs/en/guides/deploy/microsoft-azure.mdx
index 9eba99e7c30ac..889968503d19d 100644
--- a/src/content/docs/en/guides/deploy/microsoft-azure.mdx
+++ b/src/content/docs/en/guides/deploy/microsoft-azure.mdx
@@ -40,7 +40,7 @@ The GitHub action yaml that is created for you assumes the use of node 14. This
```
"engines": {
- "node": ">=18.0.0"
+ "node": ">=22.12.0"
},
```
diff --git a/src/content/docs/en/guides/deploy/netlify.mdx b/src/content/docs/en/guides/deploy/netlify.mdx
index 1d59154bafb77..df5016fe5d20d 100644
--- a/src/content/docs/en/guides/deploy/netlify.mdx
+++ b/src/content/docs/en/guides/deploy/netlify.mdx
@@ -101,7 +101,7 @@ You can also create a new site on Netlify and link up your Git repository by ins
### Set a Node.js version
-If you are using a legacy [build image](https://docs.netlify.com/configure-builds/get-started/#build-image-selection) (Xenial) on Netlify, make sure that your Node.js version is set. Astro requires `v18.20.8` or `v20.3.0` or higher.
+If you are using a legacy [build image](https://docs.netlify.com/configure-builds/get-started/#build-image-selection) (Xenial) on Netlify, make sure that your Node.js version is set. Astro requires `v22.12.0` or higher.
You can [specify your Node.js version in Netlify](https://docs.netlify.com/configure-builds/manage-dependencies/#node-js-and-javascript) using:
- a [`.nvmrc`](https://github.com/nvm-sh/nvm#nvmrc) file in your base directory.
diff --git a/src/content/docs/en/guides/endpoints.mdx b/src/content/docs/en/guides/endpoints.mdx
index 3329a1bd64dad..51f9c9c65904b 100644
--- a/src/content/docs/en/guides/endpoints.mdx
+++ b/src/content/docs/en/guides/endpoints.mdx
@@ -47,6 +47,8 @@ import type { APIRoute } from "astro";
export const GET: APIRoute = async ({ params, request }) => {...}
```
+Note that endpoints whose URLs include a file extension (e.g. `src/pages/sitemap.xml.ts`) can only be accessed without a trailing slash (e.g. `/sitemap.xml`), regardless of your [`build.trailingSlash`](/en/reference/configuration-reference/#trailingslash) configuration.
+
### `params` and Dynamic routing
Endpoints support the same [dynamic routing](/en/guides/routing/#dynamic-routes) features that pages do. Name your file with a bracketed parameter name and export a [`getStaticPaths()` function](/en/reference/routing-reference/#getstaticpaths). Then, you can access the parameter using the `params` property passed to the endpoint function:
diff --git a/src/content/docs/en/guides/environment-variables.mdx b/src/content/docs/en/guides/environment-variables.mdx
index af2b99b85fd9e..24d3eba46ba38 100644
--- a/src/content/docs/en/guides/environment-variables.mdx
+++ b/src/content/docs/en/guides/environment-variables.mdx
@@ -58,7 +58,6 @@ Astro includes a few environment variables out of the box:
- `import.meta.env.DEV`: `true` if your site is running in development; `false` otherwise. Always the opposite of `import.meta.env.PROD`.
- `import.meta.env.BASE_URL`: The base URL your site is being served from. This is determined by the [`base` config option](/en/reference/configuration-reference/#base).
- `import.meta.env.SITE`: This is set to [the `site` option](/en/reference/configuration-reference/#site) specified in your project's `astro.config`.
-- `import.meta.env.ASSETS_PREFIX`: The prefix for Astro-generated asset links if the [`build.assetsPrefix` config option](/en/reference/configuration-reference/#buildassetsprefix) is set. This can be used to create asset links not handled by Astro.
Use them like any other environment variable.
diff --git a/src/content/docs/en/guides/images.mdx b/src/content/docs/en/guides/images.mdx
index 251cf3249509d..5f17a3b8b5266 100644
--- a/src/content/docs/en/guides/images.mdx
+++ b/src/content/docs/en/guides/images.mdx
@@ -51,7 +51,7 @@ All native HTML tags, including ` ` and ``, are also available in `.ast
For all images in `.astro` files, **the value of the image `src` attribute is determined by the location of your image file**:
- A local image from your project `src/` folder uses an import from the file's relative path.
-
+
The image and picture components use the named import directly (e.g. `src={rocket}`), while the ` ` tag uses the `src` object property of the import (e.g. `src={rocket.src}`).
- Remote and `public/` images use a URL path.
@@ -321,7 +321,7 @@ import myImage from '../assets/my_image.png'; // Image is 1600x900
Responsive images are images that adjust to improve performance across different devices. These images can resize to fit their container, and can be served in different sizes depending on your visitor's screen size and resolution.
-With [responsive image properties](/en/reference/modules/astro-assets/#responsive-image-properties) applied to the ` ` or ` ` components, Astro will automatically generate the required `srcset` and `sizes` values for your images, and apply the necessary [styles to ensure they resize correctly](#responsive-image-styles).
+With the [layout property](/en/reference/modules/astro-assets/#layout) applied to the ` ` or ` ` components, Astro will automatically generate the required `srcset` and `sizes` values for your images, and apply the necessary [styles to ensure they resize correctly](#responsive-image-styles).
When this responsive behavior is [configured globally with `image.layout`](/en/reference/configuration-reference/#imagelayout), it will apply to all image components and also to any local and remote images using [the Markdown `![]()` syntax](/en/guides/images/#images-in-markdown-files).
@@ -396,7 +396,7 @@ The global styles applied by Astro will depend on the layout type, and are desig
The styles use the [`:where()` pseudo-class](https://developer.mozilla.org/en-US/docs/Web/CSS/:where), which has a [specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascade/Specificity) of 0, meaning that it is easy to override with your own styles. Any CSS selector will have a higher specificity than `:where()`, so you can easily override the styles by adding your own styles to target the image.
-You can override the `object-fit` and `object-position` styles on a per-image basis by setting the `fit` and `position` props on the ` ` or ` ` component.
+You can override the `object-fit` and `object-position` styles on a per-image basis by setting the `fit` and `position` props on the ` ` or ` ` component.
#### Responsive images with Tailwind 4
@@ -590,8 +590,8 @@ This is a blog post
The `image` helper for the content collections schema lets you validate and import the image.
```ts title="src/content.config.ts"
-import { defineCollection } from "astro:content";
-import { z } from "astro/zod";
+import { defineCollection } from 'astro:content';
+import { z } from 'astro/zod';
const blogCollection = defineCollection({
schema: ({ image }) => z.object({
diff --git a/src/content/docs/en/guides/imports.mdx b/src/content/docs/en/guides/imports.mdx
index 2b7145046b4c6..132658cccef41 100644
--- a/src/content/docs/en/guides/imports.mdx
+++ b/src/content/docs/en/guides/imports.mdx
@@ -344,7 +344,7 @@ Additionally, glob patterns must begin with one of the following:
### `import.meta.glob()` vs `getCollection()`
-[Content collections](/en/guides/content-collections/) provide a [`getCollection()` API](/en/reference/modules/astro-content/#getcollection) for loading multiple files instead of `import.meta.glob()`. If your content files (e.g. Markdown, MDX, Markdoc) are located in collections within the `src/content/` directory, use `getCollection()` to [query a collection](/en/guides/content-collections/#querying-collections) and return content entries.
+[Content collections](/en/guides/content-collections/) provide [performant, content-focused APIs](/en/reference/modules/astro-content/) for loading multiple files instead of `import.meta.glob()`. Use `getCollection()` and `getLiveCollection()` to query your collections and return content entries.
## WASM
diff --git a/src/content/docs/en/guides/integrations-guide/cloudflare.mdx b/src/content/docs/en/guides/integrations-guide/cloudflare.mdx
index 60dd13a2e518b..b19bd21613d09 100644
--- a/src/content/docs/en/guides/integrations-guide/cloudflare.mdx
+++ b/src/content/docs/en/guides/integrations-guide/cloudflare.mdx
@@ -20,11 +20,14 @@ If you're using Astro as a static site builder, you don't need an adapter.
Learn how to deploy your Astro site in our [Cloudflare deployment guide](/en/guides/deploy/cloudflare/).
+:::tip[Upgrading to Astro 6?]
+Astro 6 requires an upgrade to v13 of this adapter. See the [Cloudflare adapter upgrade instructions for Astro 6](#upgrading-to-v13-and-astro-6) for breaking changes and migration guidance.
+:::
+
## Why Astro Cloudflare
Cloudflare's [Developer Platform](https://developers.cloudflare.com/) lets you develop full-stack applications with access to resources such as storage and AI, all deployed to a global edge network. This adapter builds your Astro project for deployment through Cloudflare.
-
## Installation
Astro includes an `astro add` command to automate the setup of official integrations. If you prefer, you can [install integrations manually](#manual-install) instead.
@@ -77,44 +80,24 @@ Now, you can enable [on-demand rendering per page](/en/guides/on-demand-renderin
2. Add the adapter to your `astro.config.mjs` file:
- ```js title="astro.config.mjs" ins={2,5}
- import { defineConfig } from 'astro/config';
- import cloudflare from '@astrojs/cloudflare';
-
- export default defineConfig({
- adapter: cloudflare(),
- });
- ```
+ ```js title="astro.config.mjs" ins={2,5}
+ import { defineConfig } from 'astro/config';
+ import cloudflare from '@astrojs/cloudflare';
-3. Create a [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/):
-
- ```jsonc title="wrangler.jsonc"
- {
- "main": "dist/_worker.js/index.js",
- "name": "my-astro-app",
- // Update to today's date
- "compatibility_date": "2025-03-25",
- "compatibility_flags": [
- "nodejs_compat",
- "global_fetch_strictly_public"
- ],
- "assets": {
- "binding": "ASSETS",
- "directory": "./dist"
- },
- "observability": {
- "enabled": true
- }
- }
- ```
-
-4. Create a `.assetsignore` file in your `public/` folder, and add the following lines to it:
+ export default defineConfig({
+ adapter: cloudflare(),
+ });
+ ```
- ```txt title="public/.assetsignore"
- _worker.js
- _routes.json
- ```
+3. Astro will automatically generate a default configuration, using the package.json name field or the folder name as the Worker name. You can optionally create a [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/) if you need custom settings. This example declares Cloudflare KV bindings:
+ ```jsonc title="wrangler.jsonc"
+ {
+ "name": "my-astro-app",
+ // Add your bindings here, e.g.:
+ // "kv_namespaces": [{ "binding": "MY_KV", "id": "" }]
+ }
+ ```
## Options
@@ -135,142 +118,38 @@ This functionality is enabled by default. If you'd like to disable, set `cloudfl
### `imageService`
-**Type:** `'passthrough' | 'cloudflare' | 'compile' | 'custom'`
+**Type:** `'passthrough' | 'cloudflare' | 'cloudflare-binding' | 'compile' | 'custom'`
**Default:** `'compile'`
Determines which image service is used by the adapter. The adapter will default to `compile` mode when an incompatible image service is configured. Otherwise, it will use the globally configured image service:
-* **`cloudflare`:** Uses the [Cloudflare Image Resizing](https://developers.cloudflare.com/images/image-resizing/) service.
-* **`passthrough`:** Uses the existing [`noop`](/en/guides/images/#configure-no-op-passthrough-service) service.
-* **`compile`:** Uses Astro's default service (sharp), but only on pre-rendered routes at build time. For pages rendered on-demand, all `astro:assets` features are disabled.
-* **`custom`:** Always uses the image service configured in [Image Options](/en/reference/configuration-reference/#image-options). **This option will not check to see whether the configured image service works in Cloudflare's `workerd` runtime.**
+- **`cloudflare`:** Uses the [Cloudflare Image Resizing](https://developers.cloudflare.com/images/image-resizing/) service.
+- **`cloudflare-binding`:** Uses the [Cloudflare Images binding](https://developers.cloudflare.com/images/transform-images/bindings/) for image transformation. The binding is automatically provisioned when you deploy.
+- **`passthrough`:** Uses the existing [`noop`](/en/guides/images/#configure-no-op-passthrough-service) service.
+- **`compile`:** Uses Astro's default service (Sharp), but only on pre-rendered routes at build time. For pages rendered on demand, all `astro:assets` features are disabled.
+- **`custom`:** Always uses the image service configured in [Image Options](/en/reference/configuration-reference/#image-options). **This option will not check to see whether the configured image service works in Cloudflare's `workerd` runtime.**
```js title="astro.config.mjs" ins={6}
-import { defineConfig } from "astro/config";
-import cloudflare from '@astrojs/cloudflare';
-
-export default defineConfig({
- adapter: cloudflare({
- imageService: 'cloudflare'
- }),
-})
-```
-
-### `platformProxy`
-
-Determines whether and how the Cloudflare runtime is added to `astro dev`. It contains proxies to local `workerd` bindings and emulations of Cloudflare specific values, allowing the emulation of the runtime in the Node.js dev process. Read more about the [Cloudflare Runtime](#cloudflare-runtime).
-
-:::note
-Proxies provided by this are a best effort emulation of the real production. Although they are designed to be as close as possible to the real thing, there might be a slight differences and inconsistencies between the two.
-:::
-
-#### `platformProxy.enabled`
-
-**Type:** `boolean`
-**Default:** `true`
-
-
-Determines whether to enable the Cloudflare runtime in development mode.
-
-#### `platformProxy.configPath`
-
-**Type:** `string`
-**Default:** `undefined`
-
-
-Defines the path to the Wrangler configuration file. If no value is set, it tracks `wrangler.toml`, `wrangler.json`, and `wrangler.jsonc` in the project root.
-
-#### `platformProxy.environment`
-
-**Type:** `string`
-**Default:** `undefined`
-
-
-Sets the [Cloudflare environment](https://developers.cloudflare.com/workers/wrangler/environments/) to use. You must select an environment defined in the Wrangler configuration file, otherwise an error occurs.
-
-#### `platformProxy.persist`
-
-**Type:** `boolean | { path: string }`
-**Default:** `true`
-
-
-Sets whether and where to save binding data locally to the file system.
-
-- If set to `true`, binding data is stored in `.wrangler/state/v3/`. It is the same as the default setting for wrangler.
-- If set to `false`, binding data is not stored in file system.
-- If set to `{ path: string }`, binding data is stored in the specified path.
-
-:::note
-`wrangler`'s `--persist-to` option adds a sub directory called `v3` under the hood while the `@astrojs/cloudflare` `persist` property does not. For example, to reuse the same location as running `wrangler dev --persist-to ./my-directory`, you must specify: `persist: { path: "./my-directory/v3" }`.
-:::
-
-The following configuration shows an example of enabling the Cloudflare runtime when running the development server, as well as using a `wrangler.json` config file. It also specifies a custom location for persisting data to the filesystem:
-
-
-```js
-import cloudflare from '@astrojs/cloudflare';
import { defineConfig } from 'astro/config';
+import cloudflare from '@astrojs/cloudflare';
-export default defineConfig({
- adapter: cloudflare({
- platformProxy: {
- enabled: true,
- configPath: 'wrangler.json',
- persist: {
- path: './.cache/wrangler/v3'
- },
- },
- }),
-});
-```
-### `routes.extend`
-
-On Cloudflare Workers, this option is not applicable. Refer to [Routing on Cloudflare Workers](#routing-on-cloudflare-workers) for more information.
-
-On Cloudflare Pages, this option allows you to add or exclude custom patterns (e.g. `/fonts/*`) to the generated `_routes.json` file that determines which routes are generated on-demand. This can be useful if you need to add route patterns which cannot be automatically generated, or exclude prerendered routes.
-
-More information about the custom route patterns can be found in [Cloudflare's routing docs](https://developers.cloudflare.com/pages/functions/routing/#functions-invocation-routes). Any routes specified are not automatically deduplicated and will be appended to the existing routes as is.
-
-#### `routes.extend.include`
-
-
-**Type:** `{ pattern: string }[]`
-**Default:** `undefined`
-
-
-Configures additional routes to be generated on demand by the Cloudflare adapter in the `routes.extend.include` array.
-
-#### `routes.extend.exclude`
-
-
-**Type:** `{ pattern: string }[]`
-**Default:** `undefined`
-
-
-Configures routes to be excluded from on-demand rendering in the `routes.extend.exclude` array. These routes will be prerendered and served statically instead, and will not invoke the server function. Additionally you can use this option to serve any static asset (e.g. images, fonts, css, js, html, txt, json, etc.) files directly without routing the request through the server function.
-
-```js title="astro.config.mjs"
export default defineConfig({
adapter: cloudflare({
- routes: {
- extend: {
- include: [{ pattern: '/static' }], // Route a prerended page to the server function for on-demand rendering
- exclude: [{ pattern: '/pagefind/*' }], // Use Starlight's pagefind search, which is generated statically at build time
- }
- },
+ imageService: 'cloudflare-binding',
}),
});
```
### `sessionKVBindingName`
+
**Type:** `string`
**Default:** `SESSION`
-The `sessionKVBindingName` option allows you to specify the name of the KV binding used for session storage. By default, this is set to `SESSION`, but you can change it to match your own KV binding name. See [Sessions](#sessions) for more information.
+Sets the name of the KV binding used for session storage. By default, the KV namespace is automatically provisioned when you deploy, and is named `SESSION`. You can change this name by setting the binding manually in your wrangler config. See [Sessions](#sessions) for more information.
```js title="astro.config.mjs" "MY_SESSION_BINDING"
export default defineConfig({
@@ -280,171 +159,126 @@ export default defineConfig({
});
```
-### `workerEntryPoint`
-
-
-**Type:** `{ path: string | URL, namedExports: string[] }`
-**Default:** `{ path: '@astrojs/cloudflare/entrypoints/server.js', namedExports: [] }`
-
-
-
-
-A configuration object to specify the [workerEntryPoint](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/rpc/) for your Cloudflare Worker when you use the `astro build` command.
-
-It allows you to optionally specify both a custom file `path` and `namedExports`:
-
-```js title="astro.config.mjs"
-import cloudflare from '@astrojs/cloudflare';
-import { defineConfig } from 'astro/config';
-
-export default defineConfig({
- adapter: cloudflare({
- workerEntryPoint: {
- path: 'src/worker.ts',
- namedExports: ['MyDurableObject']
- }
- }),
-});
+```jsonc title="wrangler.jsonc"
+{
+ "kv_namespaces": [
+ {
+ "binding": "MY_SESSION_BINDING",
+ }
+ ]
+}
```
-#### `workerEntryPoint.path`
+### `imagesBindingName`
-
**Type:** `string`
-**Default:** `@astrojs/cloudflare/entrypoints/server.js`
-
+**Default:** `IMAGES`
-The path to the entry file. This should be a relative path from the root of your Astro project.
+Sets the name of the Images binding used when [`imageService`](#imageservice) is set to `cloudflare-binding`. By default, the binding is automatically provisioned with the name `IMAGES` when you deploy. You can change it by setting the binding manually in your wrangler config:
-By default, the adapter uses a generic entry file, which only supports the `fetch` handler.
+```js title="astro.config.mjs" "MY_IMAGES"
+export default defineConfig({
+ adapter: cloudflare({
+ imageService: 'cloudflare-binding',
+ imagesBindingName: 'MY_IMAGES',
+ }),
+});
+```
-To support other [Cloudflare invocation handlers](https://developers.cloudflare.com/workers/observability/logs/workers-logs/#invocation-logs), you can create a custom file to use as the entry point. This is useful if you want to use features that require other handlers (e.g. Durable Objects, Cloudflare Queues, Scheduled Invocations).
+```jsonc title="wrangler.jsonc"
+{
+ "images": {
+ "binding": "MY_IMAGES"
+ }
+}
+```
-#### `workerEntryPoint.namedExports`
+## Cloudflare runtime
-
+The Cloudflare runtime gives you access to environment variables, bindings to Cloudflare resources, and other Cloudflare-specific APIs.
-**Type:** `[]`
-**Default:** `[]`
-
-
+### Environment variables and bindings
-An array of named exports to use for the entry file.
+Environment variables and bindings are defined in your `wrangler.jsonc` configuration file.
-Provide any additional defined named exports of your [custom entry file](#creating-a-custom-cloudflare-worker-entry-file) (e.g. `DurableObject`). If not provided, only default exports will be included.
-#### Creating a custom Cloudflare Worker entry file
-The custom entry file must export the `createExports()` function with a `default` export including all the handlers you need.
+Define [environment variables](https://developers.cloudflare.com/workers/configuration/environment-variables/#add-environment-variables-via-wrangler) that do not store sensitive information in `wrangler.jsonc`:
-The following example entry file registers a Durable Object and a queue handler:
+```jsonc title="wrangler.jsonc"
+{
+ "vars": {
+ "MY_VARIABLE": "test",
+ },
+}
+```
-```ts title="src/worker.ts"
-import type { SSRManifest } from 'astro';
-import { App } from 'astro/app';
-import { handle } from '@astrojs/cloudflare/handler'
-import { DurableObject } from 'cloudflare:workers';
+[Secrets](https://developers.cloudflare.com/workers/configuration/secrets/) are a special type of environment variable that allow you to attach encrypted text values to your Worker. They need to be defined differently to ensure they are not visible within Wrangler or Cloudflare dashboard after you set them.
-class MyDurableObject extends DurableObject {
- constructor(ctx: DurableObjectState, env: Env) {
- super(ctx, env)
- }
-}
+To define `secrets`, add them through the [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) rather than in your Wrangler config file:
-export function createExports(manifest: SSRManifest) {
- const app = new App(manifest);
- return {
- default: {
- async fetch(request, env, ctx) {
- await env.MY_QUEUE.send("log");
- return handle(manifest, app, request, env, ctx);
- },
- async queue(batch, _env) {
- let messages = JSON.stringify(batch.messages);
- console.log(`consumed from our queue: ${messages}`);
- }
- } satisfies ExportedHandler,
- MyDurableObject: MyDurableObject,
- }
-}
+```bash
+npx wrangler secret put
```
-## Cloudflare runtime
+To set secrets for local development, add a `.dev.vars` file to the root of the Astro project:
-### Usage
-
-The Cloudflare runtime gives you access to environment variables and bindings to Cloudflare resources defined in your `wrangler.toml`/`wrangler.jsonc` configuration file.
+```ini title=".dev.vars"
+DB_PASSWORD=myPassword
+```
-You can access the bindings from `Astro.locals.runtime`:
+Cloudflare environment variables and secrets can be imported from `"cloudflare:workers"`:
```astro title="src/pages/index.astro"
---
-const { env } = Astro.locals.runtime;
+import { env } from 'cloudflare:workers';
+
+const myVariable = env.MY_VARIABLE;
+const myKVNamespace = env.MY_KV;
---
```
-You can access the runtime from API endpoints through `context.locals`:
-```js title="src/pages/api/someFile.js"
-export function GET(context) {
- const runtime = context.locals.runtime;
+They are also compatible with the [`astro:env` API](/en/guides/environment-variables/#type-safe-environment-variables):
- return new Response('Some body');
-}
+```js
+import { MY_VARIABLE } from 'astro:env/server';
```
See the [list of all supported bindings](https://developers.cloudflare.com/workers/wrangler/api/#supported-bindings) in the Cloudflare documentation.
+### The `cf` object
-### Environment variables and secrets
+The Cloudflare [`cf` object](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties) contains request metadata such as geolocation information. Access it directly from the request:
-The Cloudflare runtime treats environment variables as a type of binding.
-
-For example, you can define an [environment variable](https://developers.cloudflare.com/workers/configuration/environment-variables/#add-environment-variables-via-wrangler) in `wrangler.jsonc` as follows:
-
-```jsonc title="wrangler.jsonc"
-{
- "vars" : {
- "MY_VARIABLE": "test"
- }
-}
-```
-
-Secrets are a special type of environment variable that allow you to attach encrypted text values to your Worker. They need to be defined differently to ensure they are not visible after you set them.
-
-To define `secrets`, add them through the [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) rather than in your Wrangler config file.
-
-```bash
-npx wrangler secret put
+```astro title="src/pages/index.astro"
+---
+const cf = Astro.request.cf;
+const country = cf?.country;
+---
```
-To set secrets for local development, you also need to add a `.dev.vars` file to the root of the Astro project:
-
-```ini title=".dev.vars"
-DB_PASSWORD=myPassword
-```
+### Execution context
-You can then access environment variables, including secrets, from the `env` object available from `Astro.locals.runtime`:
+Access the Cloudflare [`ExecutionContext`](https://developers.cloudflare.com/workers/runtime-apis/context/) through `Astro.locals.cfContext`. This is useful for operations like [`waitUntil()`](https://developers.cloudflare.com/workers/runtime-apis/context/#waituntil), or accessing [Durable Object exports](https://developers.cloudflare.com/workers/runtime-apis/context/#exports) within your page.
```astro title="src/pages/index.astro"
---
-const { env } = Astro.locals.runtime;
-const myVariable = env.MY_VARIABLE;
-const secret = env.DB_PASSWORD;
+const cfContext = Astro.locals.cfContext;
+cfContext.exports.Greeter.greet('Astro');
+cfContext.waitUntil(someAsyncOperation());
---
```
-Cloudflare environment variables and secrets are compatible with the [`astro:env` API](/en/guides/environment-variables/#type-safe-environment-variables).
-
### Typing
-`wrangler` provides a `types` command to generate TypeScript types for the bindings. This allows you to type locals without the need to manually type them. Refer to the [Cloudflare documentation](https://developers.cloudflare.com/workers/wrangler/commands/#types) for more information.
+`wrangler` provides a [`types`](https://developers.cloudflare.com/workers/wrangler/commands/#types) command to generate TypeScript types for your bindings. This allows you to type your environment without the need for manual type definitions.
-Every time you change your configuration files (e.g. `wrangler.toml`, `.dev.vars`) you need to run `wrangler types`.
+Run `wrangler types` every time you change your configuration files (e.g. `wrangler.jsonc`, `.dev.vars`).
:::note
-You can create a pnpm script to run `wrangler types` automatically before other commands.
+The following example shows a script configuration to run `wrangler types` automatically before other commands:
```json title="package.json"
{
@@ -457,117 +291,48 @@ You can create a pnpm script to run `wrangler types` automatically before other
}
}
```
-:::
-You can type the `runtime` object by [extending global types](/en/guides/typescript/#extending-global-types) using `Runtime`:
-
-```ts title="src/env.d.ts"
-type Runtime = import('@astrojs/cloudflare').Runtime;
-
-declare namespace App {
- interface Locals extends Runtime {
- otherLocals: {
- test: string;
- };
- }
-}
-```
+:::
## Cloudflare Platform
### Headers
-You can attach [custom headers](https://developers.cloudflare.com/pages/platform/headers/) to your responses by adding a `_headers` file in your Astro project's `public/` folder. This file will be copied to your build output directory.
-
-This is available on Cloudflare Workers and Pages.
+Add [custom headers](https://developers.cloudflare.com/workers/static-assets/headers/) for static assets by creating a `_headers` file in your Astro project's `public/` folder. This file will be copied to the build output directory. Headers in `_headers` are not applied to responses generated by your Worker code.
### Assets
-Assets built by Astro are all named with a hash and therefore can be given long cache headers. By default, Astro on Cloudflare will add such a header for these files.
-### Redirects
+Assets built by Astro are all named with a hash and, therefore, can be given long cache headers. By default, Astro on Cloudflare will add such a header for these files.
-You can declare [custom redirects](https://developers.cloudflare.com/pages/platform/redirects/) to redirect requests to a different URL. To do so, add a `_redirects` file in your Astro project's `public/` folder. This file will be copied to your build output directory.
+### Redirects
-This is available on Cloudflare Workers and Pages.
+Declare [custom redirects for static assets](https://developers.cloudflare.com/workers/static-assets/redirects/) by adding a `_redirects` file in your Astro project's `public/` folder. This file will be copied to your build output directory. For dynamic routes, [configure redirects in Astro directly](/en/guides/routing/#configured-redirects) instead.
### Routes
-#### Routing on Cloudflare Workers
Routing for static assets is based on the file structure in the build directory (e.g. `./dist`). If no match is found, this will fall back to the Worker for on-demand rendering. Read more about [static asset routing with Cloudflare Workers](https://developers.cloudflare.com/workers/static-assets/routing/).
-Unlike [Cloudflare Pages](#routing-on-cloudflare-pages), with Workers, you do not need a `_routes.json` file.
-
-Currently, the Cloudflare adapter always generates this file. To work around this, create a `.assetsignore` file in your `public/` folder, and add the following lines to it:
- ```txt title="public/.assetsignore"
- _worker.js
- _routes.json
- ```
-
-#### Routing on Cloudflare Pages
-
-For Cloudflare Pages, [routing](https://developers.cloudflare.com/pages/platform/functions/routing/#functions-invocation-routes) uses a `_routes.json` file to determine which requests are routed to the server function and which are served as static assets. By default, a `_routes.json` file will be automatically generated for your project based on its files and configuration.
-
-You can [specify additional routing patterns to follow](#routesextend) in your adapter config, or create your own custom `_routes.json` file to fully override the automatic generation.
-
-
-Creating a custom `public/_routes.json` will override the automatic generation. See [Cloudflare's documentation on creating a custom `_routes.json`](https://developers.cloudflare.com/pages/platform/functions/routing/#create-a-_routesjson-file) for more details.
-
## Sessions
-The Astro [Sessions API](/en/guides/sessions/) allows you to easily store user data between requests. This can be used for things like user data and preferences, shopping carts, and authentication credentials. Unlike cookie storage, there are no size limits on the data, and it can be restored on different devices.
-
-Astro automatically configures [Workers KV](https://developers.cloudflare.com/kv/) for session storage when using the Cloudflare adapter. Before using sessions, you need to create a KV namespace to store the data and configure a KV binding in your Wrangler config file. By default, Astro expects the KV binding to be named `SESSION`, but you can choose a different name if you prefer by setting the [`sessionKVBindingName`](#sessionkvbindingname) option in the adapter config.
-
-
+The Astro [Sessions API](/en/guides/sessions/) allows you to easily store user data between requests. This can be used for things like user data and preferences, shopping carts, and authentication credentials. Unlike cookie storage, there are no size limits on the data, and it can be restored on different devices.
-1. Create a KV namespace using the Wrangler CLI and make note of the ID of the new namespace:
+Astro automatically configures [Workers KV](https://developers.cloudflare.com/kv/) for session storage when using the Cloudflare adapter. Wrangler can [automatically provision](https://developers.cloudflare.com/workers/wrangler/configuration/#automatic-provisioning) the KV namespace when you deploy, so no manual setup is required. Alternatively, you can define the KV binding manually in your `wrangler.jsonc` file and set a custom binding name using the [`sessionKVBindingName`](#sessionkvbindingname) adapter option.
- ```sh
- npx wrangler kv namespace create "SESSION"
- ```
+```astro title="src/components/CartButton.astro"
+---
+export const prerender = false; // Not needed in 'server' mode
+const cart = await Astro.session?.get('cart');
+---
-2. Declare the KV namespace in your Wrangler config, setting the namespace ID to the one returned by the previous command:
-
-
-
- ```json title="wrangler.jsonc" ""
- {
- "kv_namespaces": [
- {
- "binding": "SESSION",
- "id": ""
- }
- ]
- }
- ```
-
-
- ```toml title="wrangler.toml" ""
- kv_namespaces = [
- { binding = "SESSION", id = "" }
- ]
- ```
-
-
-
-3. You can then use sessions in your server code:
-
- ```astro title="src/components/CartButton.astro" "Astro.session?.get('cart')"
- ---
- export const prerender = false;
- const cart = await Astro.session?.get('cart');
- ---
-
- 🛒 {cart?.length ?? 0} items
- ```
+🛒 {cart?.length ?? 0} items
+```
-
+By default, the KV binding is named `SESSION`. To use a different name, set the [`sessionKVBindingName`](#sessionkvbindingname) option in the adapter config.
:::note
Writes to Cloudflare KV are [eventually consistent](https://developers.cloudflare.com/kv/concepts/how-kv-works/#consistency) between regions. This means that changes are available immediately within the same region but may take up to 60 seconds to propagate globally. This won't affect most users as they are unlikely to switch regions between requests, but it may be a consideration for some use cases, such as VPN users.
:::
-
## Cloudflare Module Imports
The Cloudflare `workerd` runtime supports imports of some [non-standard module types](https://developers.cloudflare.com/workers/wrangler/bundling/#including-non-javascript-modules). Most additional file types are also available in Astro:
@@ -598,68 +363,244 @@ While this example is trivial, Wasm can be used to accelerate computationally in
## Node.js compatibility
-Out of the box, Cloudflare does not support the Node.js runtime APIs. With some configuration, Cloudflare does support a subset of the Node.js runtime APIs. You can find supported Node.js runtime APIs in Cloudflare's [documentation](https://developers.cloudflare.com/workers/runtime-apis/nodejs).
+Cloudflare Workers support most Node.js runtime APIs through the `nodejs_compat` compatibility flag. This includes commonly used modules like `node:buffer`, `node:crypto`, `node:path`, and many others. See the [full list of supported Node.js APIs](https://developers.cloudflare.com/workers/runtime-apis/nodejs) in Cloudflare's documentation.
+
+To enable Node.js compatibility, add the `nodejs_compat` flag to your Wrangler configuration:
+
+```jsonc title="wrangler.jsonc"
+{
+ "compatibility_flags": ["nodejs_compat"],
+}
+```
-To use these APIs, your page or endpoint must be server-side rendered (not pre-rendered) and must use the `import {} from 'node:*'` import syntax.
+Then use the `node:*` import syntax in your server-side code:
-```js title="pages/api/endpoint.js"
-export const prerender = false;
+```js title="src/pages/api/endpoint.js"
+export const prerender = false; // Not needed in 'server' mode
import { Buffer } from 'node:buffer';
```
-You'll also need to modify the `vite` configuration in your Astro config to allow for the `node:*` import syntax:
+For Node.js APIs not yet supported in the Workers runtime, Wrangler can inject polyfills (requires `nodejs_compat` and a compatibility date of 2024-09-23 or later).
-```js title="astro.config.mjs" ins={6-10}
-import {defineConfig} from "astro/config";
-import cloudflare from '@astrojs/cloudflare';
+See the [Cloudflare documentation on Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs/) for the complete list of supported APIs and configuration details.
+
+## Local preview
+
+After building your project with `astro build`, use `astro preview` to test your Cloudflare Workers application locally. The preview runs using Cloudflare's `workerd` runtime, closely mirroring production behavior.
+
+### Meaningful error messages
+By default, errors occurring while running your application in Wrangler are minified. For better debugging, add `vite.build.minify = false` to your `astro.config.mjs`:
+
+```js title="astro.config.mjs" ins={3-7}
export default defineConfig({
- adapter: cloudflare({}),
+ adapter: cloudflare(),
vite: {
- ssr: {
- external: ['node:buffer'],
- },
- },
-})
+ build: {
+ minify: false,
+ },
+ },
+});
```
-Additionally, you'll need to follow Cloudflare's documentation on how to enable support. For detailed guidance, please refer to the [Cloudflare documentation on enabling Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs/).
+## Using with Cloudflare Pages
-:::note[Package Compatibility Implications]
-If a project imports a package into the server that uses the Node.js runtime APIs, this can cause issues when deploying to Cloudflare. This issue arises with package that do not use the `node:*` import syntax. It is recommended that you contact the authors of the package to determine if the package supports the above import syntax. If the package does not support this, you may need to use a different package.
+The Cloudflare adapter deploys to Cloudflare Workers by default. To deploy to Cloudflare Pages instead, additional manual configuration is required.
+
+:::caution
+Cloudflare recommends using Workers for new projects. See Cloudflare's [migration guide from Pages to Workers](https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/) for more information if you have an existing project using Pages.
:::
-## Preview with Wrangler
+
+1. Configure your build output directories in `astro.config.mjs`:
-To use [`wrangler`](https://developers.cloudflare.com/workers/wrangler/) to run your application locally, update the preview script.
+ ```js title="astro.config.mjs" ins={6-9}
+ import { defineConfig } from 'astro/config';
+ import cloudflare from '@astrojs/cloudflare';
-For Workers:
+ export default defineConfig({
+ adapter: cloudflare(),
+ build: {
+ client: './',
+ server: './_worker.js',
+ },
+ });
+ ```
-```json title="package.json"
-"preview": "wrangler dev"
+2. Create a `_routes.json` file in your `public/` folder to route requests to your Worker:
+
+ ```jsonc title="public/_routes.json"
+ {
+ "version": 1,
+ "include": ["/*"], // Alternatively, specify specific routes
+ "exclude": ["/static/*"] // Exclude static assets if needed
+ }
+ ```
+
+ See the [Cloudflare documentation on routing with Pages](https://developers.cloudflare.com/pages/functions/routing/#create-a-_routesjson-file) for more details.
+
+
+## Upgrading to v13 and Astro 6
+
+Astro 6 brings significant improvements to the Cloudflare development experience and requires `@astrojs/cloudflare` v13 or later. Now, `astro dev` uses Cloudflare's Vite plugin and `workerd` runtime to closely mirror production behavior.
+
+See [the Astro 6 upgrade guide](/en/guides/upgrade-to/v6/) for full instructions on upgrading Astro itself.
+
+### Development server now uses workerd
+
+The biggest change for Cloudflare users in Astro 6 is that `astro dev` and `astro preview` now use the Cloudflare Vite plugin to run your site using the real Workers runtime (`workerd`) instead of Node.js. This means your development environment is now a much closer replica of your production environment, with the same runtime, APIs, and behavior.
+
+This change helps you catch issues during development that would have previously only appeared in production, and features like Durable Objects, R2 bindings, and Workers AI now work exactly as they do when deployed to Cloudflare's platform.
+
+This change is transparent for most projects. If your project had special configuration for `astro dev` or was relying on Node.js-specific behavior in development, adjust your code or configuration accordingly.
+
+### Changed: Wrangler entrypoint configuration
+
+Previously, the `main` field in your Wrangler configuration pointed to the built worker file (e.g. `dist/_worker.js/index.js`). With Astro 6, this has changed to point to a new unified entrypoint provided by the Cloudflare adapter: `@astrojs/cloudflare/entrypoints/server`.
+
+Update your `wrangler.jsonc` to use the new entrypoint:
+
+```jsonc title="wrangler.jsonc" del={2} ins={3}
+{
+ "main": "dist/_worker.js/index.js",
+ "main": "@astrojs/cloudflare/entrypoints/server",
+ "name": "my-astro-app",
+ // ... rest of config
+}
```
-For Pages:
+This single entrypoint handles both `astro dev` and production deployments.
-```json title="package.json"
-"preview": "wrangler pages dev ./dist"
+### Removed: `Astro.locals.runtime` API
+
+The `Astro.locals.runtime` object has been removed in favor of direct access to Cloudflare Workers APIs. Access environment variables, the `cf` object, caches, and execution context directly through the provided interfaces.
+
+**Accessing environment variables:**
+
+Previously, environment variables were accessed through `Astro.locals.runtime.env`. Now import `env` directly instead:
+
+```js del={1} ins={2}
+const { env } = Astro.locals.runtime;
+import { env } from 'cloudflare:workers';
```
-Developing with [`wrangler`](https://developers.cloudflare.com/workers/wrangler/) gives you access to [Cloudflare bindings](https://developers.cloudflare.com/pages/platform/functions/bindings), [environment variables](https://developers.cloudflare.com/pages/platform/functions/bindings/#environment-variables), and the [cf object](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties). Getting hot reloading of the Astro dev server to work with Wrangler might require custom setup. See [community examples](https://github.com/withastro/roadmap/discussions/590).
+**Accessing the `cf` object:**
-### Meaningful error messages
+Previously, the `cf` object was accessed through `Astro.locals.runtime.cf`. Now access it directly from the request:
-Currently, errors during running your application in Wrangler are not very useful, due to the minification of your code. For better debugging, you can add `vite.build.minify = false` setting to your `astro.config.mjs`.
+```js del={1} ins={2}
+const { cf } = Astro.locals.runtime;
+const cf = Astro.request.cf;
+```
-```js title="astro.config.mjs" ins={3-7}
-export default defineConfig({
- adapter: cloudflare(),
- vite: {
- build: {
- minify: false,
- },
+**Accessing the caches API:**
+
+Previously, the caches API was accessed through `Astro.locals.runtime.caches`. Now use the global `caches` object directly:
+
+```js del={1}
+const { caches } = Astro.locals.runtime;
+
+caches.default.put(request, response);
+```
+
+**Accessing the execution context:**
+
+The `Astro.locals.runtime.ctx` object is replaced with `Astro.locals.cfContext`, which contains the Cloudflare `ExecutionContext`:
+
+```js del={1} ins={2}
+const ctx = Astro.locals.runtime.ctx;
+const ctx = Astro.locals.cfContext;
+```
+
+### Changed: Wrangler configuration file is now optional
+
+The Wrangler configuration file is now optional for simple projects. If you don't have custom configuration, such as Cloudflare bindings (KV, D1, Durable Objects, etc.), Astro will automatically generate a default configuration for you.
+
+If your `wrangler.jsonc` only contains basic configuration like this:
+
+```jsonc
+{
+ "main": "@astrojs/cloudflare/entrypoints/server",
+ "compatibility_date": "2025-05-21",
+ "assets": {
+ "directory": "./dist",
+ "binding": "ASSETS",
},
-});
+}
+```
+
+You can safely delete this file. Astro handles this configuration automatically. Alternatively, create a minimal `wrangler.jsonc` with just your project name and other custom settings:
+
+```jsonc title="wrangler.jsonc"
+{
+ "name": "my-astro-app",
+}
```
+### Changed: Custom entrypoint API
+
+If you were using a custom `workerEntryPoint` configuration in the adapter options, this has been removed. Instead, specify your custom entrypoint in your Wrangler configuration and create a standard Cloudflare Worker export object directly, rather than using the `createExports()` function.
+
+
+1. Remove the `workerEntryPoint` option from your adapter config:
+
+ ```js title="astro.config.mjs" del={6-9}
+ import { defineConfig } from 'astro/config';
+ import cloudflare from '@astrojs/cloudflare';
+
+ export default defineConfig({
+ adapter: cloudflare({
+ workerEntryPoint: {
+ path: 'src/worker.ts',
+ namedExports: ['MyDurableObject'],
+ },
+ }),
+ });
+ ```
+
+2. Specify the entrypoint in `wrangler.jsonc` instead:
+
+ ```jsonc title="wrangler.jsonc"
+ {
+ "main": "./src/worker.ts"
+ }
+ ```
+
+3. Update your custom worker entry file to use standard Worker syntax. Import the handler from `@astrojs/cloudflare/entrypoints/server` and export a standard Cloudflare Worker object, alongside any custom exports like Durable Objects:
+
+ ```ts title="src/worker.ts"
+ import handler from '@astrojs/cloudflare/entrypoints/server';
+ import { DurableObject } from 'cloudflare:workers';
+
+ export class MyDurableObject extends DurableObject {
+ // ...
+ }
+
+ export default {
+ async fetch(request, env, ctx) {
+ await env.MY_QUEUE.send('log');
+ return handler.fetch(request, env, ctx);
+ },
+ async queue(batch, _env) {
+ let messages = JSON.stringify(batch.messages);
+ console.log(`consumed from our queue: ${messages}`);
+ },
+ } satisfies ExportedHandler;
+ ```
+
+
+The manifest is now created internally by the adapter, so it does not need to be passed to your handler.
+
+### New: `astro preview` support
+
+Use `astro preview` to test your Cloudflare Workers application locally before deploying. The preview runs using Cloudflare's `workerd` runtime, closely mirroring production behavior. Run `astro build` followed by `astro preview` to start the preview server.
+
+### Deprecated: Cloudflare Pages support
+
+The Astro Cloudflare adapter now only supports deploying to Cloudflare Workers by default. If you are currently deploying to Cloudflare Pages, consider migrating to Workers for the best experience and feature support.
+
+See Cloudflare's [migration guide from Pages to Workers](https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/) for detailed migration instructions.
+
+If you need to continue using Cloudflare Pages, see [Using with Cloudflare Pages](#using-with-cloudflare-pages) for the required manual configuration.
+
[astro-integration]: /en/guides/integrations-guide/
diff --git a/src/content/docs/en/guides/integrations-guide/markdoc.mdx b/src/content/docs/en/guides/integrations-guide/markdoc.mdx
index eb2307ce5acdd..f2e6f91527758 100644
--- a/src/content/docs/en/guides/integrations-guide/markdoc.mdx
+++ b/src/content/docs/en/guides/integrations-guide/markdoc.mdx
@@ -113,7 +113,7 @@ Markdoc files can only be used within content collections. Add entries to any co
- quick-start.mdoc
-Then, query your collection using the [Content Collection APIs](/en/guides/content-collections/#querying-collections):
+Then, [query and display your posts and collections](/en/guides/content-collections/#querying-build-time-collections):
```astro title="src/pages/why-markdoc.astro"
---
diff --git a/src/content/docs/en/guides/integrations-guide/mdx.mdx b/src/content/docs/en/guides/integrations-guide/mdx.mdx
index 56cd324fb1165..c799f48f3ca69 100644
--- a/src/content/docs/en/guides/integrations-guide/mdx.mdx
+++ b/src/content/docs/en/guides/integrations-guide/mdx.mdx
@@ -96,9 +96,9 @@ It also adds extra features to standard MDX, including support for Markdown-styl
`.mdx` files must be written in [MDX syntax](https://mdxjs.com/docs/what-is-mdx/#mdx-syntax) rather than Astro’s HTML-like syntax.
-### Using MDX with content collections
+### Using local MDX with content collections
-To include MDX files in a content collection, make sure that your [collection loader](/en/guides/content-collections/#defining-the-collection-loader) is configured to load content from `.mdx` files:
+To include your local MDX files in a content collection, make sure that your [collection loader](/en/guides/content-collections/#build-time-collection-loaders) is configured to load content from `.mdx` files:
```js title="src/content.config.ts" ins="mdx"
import { defineCollection } from 'astro:content';
diff --git a/src/content/docs/en/guides/integrations-guide/netlify.mdx b/src/content/docs/en/guides/integrations-guide/netlify.mdx
index 7c72f01a5ee39..d952178d065e1 100644
--- a/src/content/docs/en/guides/integrations-guide/netlify.mdx
+++ b/src/content/docs/en/guides/integrations-guide/netlify.mdx
@@ -424,14 +424,14 @@ Enables specifying custom headers for prerendered pages in Netlify's configurati
If enabled, the adapter will save [static headers in the Framework API config file](https://docs.netlify.com/frameworks-api/#headers) when provided by Astro features, such as Content Security Policy.
-For example, when [experimental Content Security Policy](/en/reference/experimental-flags/csp/) is enabled, `experimentalStaticHeaders` can be used to add the CSP `headers` to your Netlify configuration, instead of creating a ` ` element:
+For example, when [Content Security Policy](/en/reference/configuration-reference/#securitycsp) is enabled, `experimentalStaticHeaders` can be used to add the CSP `headers` to your Netlify configuration, instead of creating a ` ` element:
```js title="astro.config.mjs" {9}
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';
export default defineConfig({
- experimental: {
+ security: {
csp: true
},
adapter: netlify({
diff --git a/src/content/docs/en/guides/integrations-guide/node.mdx b/src/content/docs/en/guides/integrations-guide/node.mdx
index a794acf66582e..8c7a264500fb5 100644
--- a/src/content/docs/en/guides/integrations-guide/node.mdx
+++ b/src/content/docs/en/guides/integrations-guide/node.mdx
@@ -144,15 +144,14 @@ export default defineConfig({
If enabled, the adapter will serve the headers of prerendered pages using the `Response` object when provided by Astro features, such as Content Security Policy.
-For example, when [experimental Content Security Policy](/en/reference/experimental-flags/csp/) is enabled, `experimentalStaticHeaders` can be used to add the CSP headers to the `Response` object instead of creating a ` ` element:
+For example, when [Content Security Policy](/en/reference/configuration-reference/#securitycsp) is enabled, `experimentalStaticHeaders` can be used to add the CSP headers to the `Response` object instead of creating a ` ` element:
```js title="astro.config.mjs" {10}
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
export default defineConfig({
- experimental: {
- csp: true
+ security csp: true
},
adapter: node({
mode: 'standalone',
diff --git a/src/content/docs/en/guides/integrations-guide/vercel.mdx b/src/content/docs/en/guides/integrations-guide/vercel.mdx
index c101b4e3d89dc..8c5fa235f7869 100644
--- a/src/content/docs/en/guides/integrations-guide/vercel.mdx
+++ b/src/content/docs/en/guides/integrations-guide/vercel.mdx
@@ -520,14 +520,14 @@ Enables specifying custom headers for prerendered pages in Vercel's configuratio
If enabled, the adapter will save [static headers in the Vercel `vercel.json` file](https://vercel.com/docs/project-configuration#headers) when provided by Astro features, such as Content Security Policy.
-For example, when [experimental Content Security Policy](/en/reference/experimental-flags/csp/) is enabled, `experimentalStaticHeaders` can be used to add the CSP `headers` to your Vercel configuration, instead of creating a ` ` element:
+For example, when [Content Security Policy](/en/reference/configuration-reference/#securitycsp) is enabled, `experimentalStaticHeaders` can be used to add the CSP `headers` to your Vercel configuration, instead of creating a ` ` element:
```js title="astro.config.mjs" {9}
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';
export default defineConfig({
- experimental: {
+ security: {
csp: true
},
adapter: vercel({
diff --git a/src/content/docs/en/guides/internationalization.mdx b/src/content/docs/en/guides/internationalization.mdx
index 3180d449571b5..7fc1b1a3d3174 100644
--- a/src/content/docs/en/guides/internationalization.mdx
+++ b/src/content/docs/en/guides/internationalization.mdx
@@ -170,15 +170,11 @@ Set this option when all routes will have their `/locale/` prefix in their URL a
- URLs without a locale prefix, (e.g. `example.com/about/`) will return a 404 (not found) status code unless you specify a [fallback strategy](#fallback).
-### `redirectToDefaultLocale`
+#### Opting out of redirects for the home URL
-
+Even with your default locale routes prefixed, this behaviour does not apply by default to your site's index page. This allows you to have a home page that exists outside of your configured locale structure, where all of your localized routes are prefixed except the home URL of your site.
-Configures whether or not the home URL (`/`) generated by `src/pages/index.astro` will redirect to `/`.
-
-Setting `prefixDefaultLocale: true` will also automatically set `redirectToDefaultLocale: true` in your `routing` config object. By default, the required `src/pages/index.astro` file will automatically redirect to the index page of your default locale.
-
-You can opt out of this behavior by [setting `redirectToDefaultLocale: false`](/en/reference/configuration-reference/#i18nroutingredirecttodefaultlocale). This allows you to have a site home page that exists outside of your configured locale folder structure.
+You can opt out of this behavior so that your main site URL will also redirect to a prefixed, localized route for your default locale. When `prefixDefaultLocale: true` is set, you can additionally configure `redirectToDefaultLocale: true`. This will ensure that the home URL (`/`) generated by `src/pages/index.astro` will redirect to `/[defaultLocale]/`.
### `manual`
diff --git a/src/content/docs/en/guides/markdown-content.mdx b/src/content/docs/en/guides/markdown-content.mdx
index 1a81d7fd47591..b0eca2f7cdc21 100644
--- a/src/content/docs/en/guides/markdown-content.mdx
+++ b/src/content/docs/en/guides/markdown-content.mdx
@@ -401,7 +401,7 @@ When using the frontmatter `layout` property, you must include the `
diff --git a/src/content/docs/en/guides/upgrade-to/v5.mdx b/src/content/docs/en/guides/upgrade-to/v5.mdx
index 8b2c6157f1c16..f0c4d913e0259 100644
--- a/src/content/docs/en/guides/upgrade-to/v5.mdx
+++ b/src/content/docs/en/guides/upgrade-to/v5.mdx
@@ -1111,8 +1111,6 @@ function useRoute(route: IntegrationRouteData) {
}
```
-See the [API reference for `IntegrationRouteData`](/en/reference/integrations-reference/#integrationroutedata).
-
### Changed: `distURL` is now an array (Integrations API)
@@ -1138,7 +1136,7 @@ if (route.distURL) {
}
```
-See the [API reference for `IntegrationRouteData`](/en/reference/integrations-reference/#integrationroutedata).
+See the [API reference for `distURL`](/en/reference/integrations-reference/#routedatadisturl).
### Changed: Arguments passed to `app.render()` (Adapter API)
diff --git a/src/content/docs/en/guides/upgrade-to/v6.mdx b/src/content/docs/en/guides/upgrade-to/v6.mdx
new file mode 100644
index 0000000000000..aead45f1f6a0b
--- /dev/null
+++ b/src/content/docs/en/guides/upgrade-to/v6.mdx
@@ -0,0 +1,1491 @@
+---
+title: Upgrade to Astro v6
+description: How to upgrade your project to Astro v6.0.
+sidebar:
+ label: v6.0
+i18nReady: true
+---
+import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro'
+import { Steps } from '@astrojs/starlight/components';
+import ReadMore from '~/components/ReadMore.astro'
+import SourcePR from '~/components/SourcePR.astro'
+
+This guide will help you migrate from Astro v5 to Astro v6.
+
+Need to upgrade an older project to v5 first? See our [older migration guide](/en/guides/upgrade-to/v5/).
+
+{/* Need to see the v5 docs? Visit this [older version of the docs site (unmaintained v5.xx snapshot)](https://v5.docs.astro.build/). */}
+
+## Upgrade Astro
+
+Update your project's version of Astro to the latest version using your package manager:
+
+
+
+ ```shell
+ # Upgrade Astro and official integrations together
+ npx @astrojs/upgrade beta
+ ```
+
+
+ ```shell
+ # Upgrade Astro and official integrations together
+ pnpm dlx @astrojs/upgrade beta
+ ```
+
+
+ ```shell
+ # Upgrade Astro and official integrations together
+ yarn dlx @astrojs/upgrade beta
+ ```
+
+
+
+You can also [upgrade your Astro integrations manually](/en/guides/integrations-guide/#manual-upgrading) if needed, and you may also need to upgrade other dependencies in your project.
+
+:::note[Need to continue?]
+After upgrading Astro, you may not need to make any changes to your project at all!
+
+But, if you notice errors or unexpected behavior, please check below for what has changed that might need updating in your project.
+:::
+
+Astro v6.0 includes [potentially breaking changes](#breaking-changes), as well as the removal and deprecation of some features.
+
+If your project doesn't work as expected after upgrading to v6.0, check this guide for an overview of all breaking changes and instructions on how to update your codebase.
+
+See [the Astro changelog](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md) for full release notes.
+
+## Dependency Upgrades
+
+Any major upgrades to Astro's dependencies may cause breaking changes in your project.
+
+### Node 22
+
+
+
+Node 18 reached its End of Life in March 2025 and Node 20 is scheduled to reach its End of Life in April 2026.
+
+Astro v6.0 drops Node 18 and Node 20 support entirely so that all Astro users can take advantage of Node's more modern features.
+
+#### What should I do?
+
+Check that both your development environment and your deployment environment are using **Node `22.12.0` or higher**.
+
+
+1. Check your local version of Node using:
+
+ ```sh
+ node -v
+ ```
+
+2. Check your [deployment environment's](/en/guides/deploy/) own documentation to verify that they support Node 22.
+
+ You can specify Node `22.12.0` for your Astro project either in a dashboard configuration setting or a `.nvmrc` file.
+
+ ```bash title=".nvmrc"
+ 22.12.0
+ ```
+
+
+### Vite 7.0
+
+
+
+Astro v6.0 upgrades to Vite v7.0 as the development server and production bundler.
+
+#### What should I do?
+
+If you are using Vite-specific plugins, configuration, or APIs, check the [Vite migration guide](https://vite.dev/guide/migration) for their breaking changes and upgrade your project as needed.
+
+Using [Astro's `getViteConfig()` helper](/en/guides/testing/#vitest) requires Vitest v3.2 (Vitest v4 is not yet supported).
+
+### Vite Environment API
+
+
+
+Astro v6.0 introduces significant changes to how Astro manages different runtime environments (client, server, and prerender) after an internal refactor to use [Vite's new Environments API](https://vite.dev/guide/api-environment).
+
+Integration and adapter maintainers should pay special attention to changes affecting these parts of the Integration API and Adapter API (full details included below with other breaking changes to these APIs):
+
+- [integration hooks and HMR access patterns](#changed-integration-hooks-and-hmr-access-patterns-integration-api)
+- [`SSRManifest` structure](#changed-ssrmanifest-interface-structure-adapter-api)
+- [generating routes with `RouteData`](#removed-routedatagenerate-adapter-api)
+- [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](https://zod.dev/v4/changelog#deprecates-email-etc) (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={2} del={1}
+email: z.string().email(),
+email: z.email(),
+```
+
+Additionally, Zod has made some [changes to handling error messages](https://zod.dev/v4/changelog#error-customization) and has dropped support for a custom `errorsMap` which was useful to redefine or translate your error messages. You may need to update any custom error messages:
+
+```ts title="src/actions/index.ts" ins={2} del={1}
+z.string().min(5, { message: "Too short." });
+z.string().min(5, { error: "Too short." });
+```
+
+Also, if you use [`.default()` with transforms](https://zod.dev/v4/changelog#default-updates), 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.
+
+These are only some of the many changes upgrading from Zod 3 to Zod 4. If you encounter any issues with your Zod schemas after upgrading to Astro 6, please consult the [Zod 4 changelog](https://zod.dev/v4/changelog) for complete upgrade guidance.
+
+Additionally, a [community codemod](https://github.com/nicoespeon/zod-v3-to-v4), which can potentially automate some of these changes when migrating from Zod 3 to Zod 4, is also available.
+
+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';
+```
+
+See more about [the `astro/zod` module](/en/reference/modules/astro-zod/).
+
+### Official Astro integrations
+
+All of [Astro's official server adapters](/en/guides/on-demand-rendering/#server-adapters) have also updated to a new major version to accompany the upgrade to Vite v7.0 with Vite's Environment API as the development server and production bundler.
+
+In particular, Astro's Cloudflare adapter has undergone significant changes, and breaking changes to your existing Cloudflare setup are expected.
+
+See the [Cloudflare adapter upgrade instructions](/en/guides/integrations-guide/cloudflare/#upgrading-to-v13-and-astro-6) for detailed migration guidance.
+
+#### What should I do?
+
+If you are using an Astro adapter for on-demand rendering or other platform-specific features, please check your specific adapter's changelog for upgrade guidance:
+
+- [`@astrojs/cloudflare` CHANGELOG](https://github.com/withastro/astro/blob/next/packages/integrations/cloudflare/CHANGELOG.md)
+- [`@astrojs/netlify` CHANGELOG](https://github.com/withastro/astro/blob/next/packages/integrations/netlify/CHANGELOG.md)
+- [`@astrojs/node` CHANGELOG](https://github.com/withastro/astro/blob/next/packages/integrations/node/CHANGELOG.md)
+- [`@astrojs/vercel` CHANGELOG](https://github.com/withastro/astro/blob/next/packages/integrations/vercel/CHANGELOG.md)
+
+## 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.
+
+### Legacy: content collections backwards compatibility
+
+In Astro 5.x, projects could delay upgrading to the new Content Layer API introduced for content collections because of some existing automatic backwards compatibility that was not previously behind a flag. This meant that it was possible to upgrade from Astro 4 to Astro 5 without updating your content collections, even if you had not enabled the `legacy.collections` flag. Projects would continue to build, and no errors or warnings would be displayed.
+
+Astro v6.0 removes this automatic legacy content collections support, along with [the `legacy.collections` flag](#removed-legacy-content-collections). All content collections must now use [the Content Layer API introduced in Astro v5.0](https://astro.build/blog/content-layer-deep-dive/) that powers all content collections.
+
+#### What should I do?
+
+If you experience content collections errors after updating to v6, [check your project for any removed legacy features](#if-you-have) that may need updating to the Content Layer API.
+
+See [the Astro v5 upgrade guide](/en/guides/upgrade-to/v5/#legacy-v20-content-collections-api) for detailed instructions on upgrading legacy collections to the new Content Layer API.
+
+If you are unable to update immediately, you can enable [the `legacy.collectionsBackwardsCompat` flag](/en/reference/legacy-flags/#collectionsbackwardscompat) as a temporary migration helper:
+
+```js title="astro.config.mjs"
+export default defineConfig({
+ legacy: {
+ collectionsBackwardsCompat: true,
+ },
+});
+```
+
+This flag preserves some legacy v4 content collections features:
+
+- Supports the legacy configuration file `src/content/config.ts`
+- Supports `type: 'content'` and `type: 'data'` without loaders
+- Preserves legacy entry API: `entry.slug` and `entry.render()`
+- Uses path-based entry IDs instead of slug-based IDs
+
+**This is a temporary migration helper.** Migrate your collections to the Content Layer API as soon as possible, then disable this flag.
+
+## Deprecated
+
+The following deprecated features are no longer supported and are no longer documented. Please update your project accordingly.
+
+Some deprecated features may temporarily continue to function until they are completely removed. Others may silently have no effect, or throw an error prompting you to update your code.
+
+### Deprecated: `Astro` in `getStaticPaths()`
+
+
+
+In Astro 5.x, it was possible to access an `Astro` object inside `getStaticPaths()`. However, despite being typed the same as the `Astro` object accessible in the frontmatter, this object only had `site` and `generator` properties. This could lead to confusion about which `Astro` object properties were available inside `getStaticPaths()`.
+
+Astro 6.0 deprecates this object for `getStaticPaths()` to avoid confusion and improves error handling when attempting to access `Astro` values that are unavailable. Using `Astro.site` or `Astro.generator` within `getStaticPaths()` will now log a deprecation warning, and accessing any other property will throw a specific error with a helpful message. In a future major version, this object will be removed entirely, and accessing `Astro.site` or `Astro.generator` will also throw an error.
+
+#### What should I do?
+
+Update your `getStaticPaths()` function if you were attempting to access any `Astro` properties inside its scope. Remove `Astro.generator` entirely, and replace all occurrences of `Astro.site()` with `import.meta.env.SITE`:
+
+```astro title="src/pages/blog/[slug].astro" del={5,6} ins={7}
+---
+import { getPages } from "../../../utils/data";
+
+export async function getStaticPaths() {
+ console.log(Astro.generator);
+ return getPages(Astro.site);
+ return getPages(import.meta.env.SITE);
+}
+---
+```
+
+Read more about [built-in environment variables such as `import.meta.env.SITE`](/en/guides/environment-variables/#default-environment-variables) that are accessible when [using `getStaticPaths()` to dynamically generate static routes](/en/guides/routing/#static-ssg-mode).
+
+### Deprecated: `import.meta.env.ASSETS_PREFIX`
+
+
+
+In Astro 5.x, it was possible to access `build.assetsPrefix` in your Astro config via the built-in environment variable `import.meta.env.ASSETS_PREFIX`. However, Astro v5.7.0 introduced the `astro:config` virtual model to expose a non-exhaustive, serializable, type-safe version of the Astro configuration which included access to `build.assetsPrefix` directly. This became the preferred way to access the prefix for Astro-generated asset links when set, although the environment variable still existed.
+
+Astro 6.0 deprecates this variable in favor of `build.assetsPrefix` from the `astro:config/server` module.
+
+#### What should I do?
+
+Replace any occurances of `import.meta.env.ASSETS_PREFIX` with the `build.assetsPrefix` import from `astro:config/server`. This is a drop-in replacement to provide the existing value, and no other changes to your code should be necessary:
+
+```ts del={4} ins={2,5}
+import { someLogic } from "./utils"
+import { build } from "astro:config/server"
+
+someLogic(import.meta.env.ASSETS_PREFIX)
+someLogic(build.assetsPrefix)
+```
+
+Read more about the [`astro:config` virtual modules](/en/reference/modules/astro-config/).
+
+### Deprecated: `astro:schema` and `z` from `astro:content`
+
+
+
+In Astro 5.x, `astro:schema` was introduced as an alias of `astro/zod`. `z` was also exported from `astro:content` for convenience. However this occasionally created confusion for users who were unsure about where they should be importing from.
+
+Astro 6.0 deprecates `astro:schema` and `z` from `astro:content` in favor of `astro/zod`.
+
+#### What should I do?
+
+Replace any occurrences of `astro:schema` with `astro/zod`:
+
+```ts del={1} ins={2}
+import { z } from "astro:schema"
+import { z } from "astro/zod"
+```
+
+Remove `z` from your `astro:content` imports and import `z` separately from `astro/zod` instead:
+
+```ts title="src/content.config.ts" del={1} ins={2-3}
+import { defineCollection, z } from "astro:content"
+import { defineCollection } from "astro:content"
+import { z } from "astro/zod"
+```
+
+See more about [defining collection schemas with Zod](/en/guides/content-collections/#defining-datatypes-with-zod).
+
+### Deprecated: exposed `astro:transitions` internals
+
+
+
+In Astro 5.x, some internals were exported from `astro:transitions` and `astro:transitions/client` that were not meant to be exposed for public use.
+
+Astro 6.0 removes the following functions and types as exports from the `astro:transitions` and `astro:transitions/client` virtual modules. These can no longer be imported in your project files:
+
+- `createAnimationScope()`
+- `isTransitionBeforePreparationEvent()`
+- `isTransitionBeforeSwapEvent()`
+- `TRANSITION_BEFORE_PREPARATION`
+- `TRANSITION_AFTER_PREPARATION`
+- `TRANSITION_BEFORE_SWAP`
+- `TRANSITION_AFTER_SWAP`
+- `TRANSITION_PAGE_LOAD`
+
+#### What should I do?
+
+Remove any occurrences of `createAnimationScope()`:
+
+```ts del={1}
+import { createAnimationScope } from 'astro:transitions';
+```
+
+Update any occurrences of the other deprecated exports:
+
+```ts del={1-4,6,9} ins={7,10}
+import {
+ isTransitionBeforePreparationEvent,
+ TRANSITION_AFTER_SWAP,
+} from 'astro:transitions/client';
+
+console.log(isTransitionBeforePreparationEvent(event));
+console.log(event.type === 'astro:before-preparation');
+
+console.log(TRANSITION_AFTER_SWAP);
+console.log('astro:after-swap');
+```
+
+Learn more about all utilities available in the [View Transitions Router API Reference](/en/reference/modules/astro-transitions/).
+
+### Deprecated: session driver string signature
+
+
+
+In Astro 5.x, any [unstorage provider](https://unstorage.unjs.io/drivers) name or a custom entrypoint could be provided to define a session driver, and options were also provided directly to the `session` configuration. However, we felt that this API was limited and inconsistent with other parts of the Astro config.
+
+Astro 6.0 deprecates the driver string signature and options in favor of a new object shape.
+
+#### What should I do?
+
+Update your session config to use the newly exported `sessionDrivers`:
+
+```js title="astro.config.mjs" del={1,6-9} ins={2,10-12}
+import { defineConfig } from 'astro/config'
+import { defineConfig, sessionDrivers } from 'astro/config'
+
+export default defineConfig({
+ session: {
+ driver: 'redis',
+ options: {
+ url: process.env.REDIS_URL
+ },
+ driver: sessionDrivers.redis({
+ url: process.env.REDIS_URL
+ }),
+ cookie: {
+ secure: true
+ },
+ ttl: 3600
+ }
+})
+```
+
+Learn more about [available session drivers](/en/reference/session-driver-reference/#building-a-session-driver).
+
+## Removed
+
+The following features have now been entirely removed from the code base and can no longer be used. Some of these features may have continued to work in your project even after deprecation. Others may have silently had no effect.
+
+Projects now containing these removed features will be unable to build, and there will no longer be any supporting documentation prompting you to remove these features.
+
+
+### Removed: legacy content collections
+
+
+
+In Astro 5.x, it was still possible to use [the original Content Collections API first introduced in Astro v2.0](https://astro.build/blog/introducing-content-collections/), **either through a `legacy` configuration flag or via built-in backwards compatibility**. These methods allowed you to upgrade to Astro v5 even if you were not yet ready or able to update your existing content collections to those powered by the new Content Layer API.
+
+Astro v6.0 removes this previously deprecated Content Collections API support entirely, including the `legacy.collections` flag **and some existing backwards compatibility that was not previously behind a flag**. All content collections must now use [the Content Layer API introduced in Astro v5.0](https://astro.build/blog/content-layer-deep-dive/) that powers all content collections. **No backwards compatibility support is available.**
+
+#### What should I do?
+
+If you had previously enabled the legacy flag, you must remove it.
+
+```ts title="astro.config.mjs" del={5}
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ legacy: {
+ collections: true,
+ }
+})
+```
+
+Additionally, if you did not upgrade your collections for Astro v5.0, ensure that your content collections are **fully updated** for the new API.
+
+Astro v5.x included some automatic backwards compatibility to allow content collections to continue to work even if they had not been updated to use the new API. Therefore, your v5 collections may contain one or more legacy features that need updating to the newer API for v6, even if your project was previously error-free.
+
+If you have [content collections errors](/en/reference/error-reference/#content-collection-errors) or warnings after upgrading to v6, use the following list to help you identify and upgrade any legacy features that may exist in your code.
+
+##### If you have...
+
+
+no content collections configuration file
+Create `src/content.config.ts` and [define your collections](/en/guides/content-collections/#defining-build-time-content-collections) in it.
+
+
+
+a configuration file located at `src/content/config.ts` / ([`LegacyContentConfigError`](/en/reference/errors/legacy-content-config-error/))
+Rename and move this file to `src/content.config.ts`
+
+
+
+a collection that does not define a `loader`/ ([`ContentCollectionMissingALoaderError`](/en/reference/errors/content-collection-missing-loader/))
+
+Import [Astro's built-in `glob()` loader](/en/guides/content-collections/#the-glob-loader) and define the `pattern` and `base` for your collection entries:
+
+```ts ins={4,7}
+// src/content.config.ts
+import { defineCollection } from 'astro:content';
+import { z } from 'astro/zod';
+import { glob } from 'astro/loaders';
+
+const blog = defineCollection({
+ loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: "./src/data/blog" }),
+ schema: z.object({
+ title: z.string(),
+ description: z.string(),
+ pubDate: z.coerce.date(),
+ updatedDate: z.coerce.date().optional(),
+ }),
+});
+```
+
+
+
+a collection that defines a collection type (`type: 'content'` or `type: 'data'`) / ([`ContentCollectionInvalidTypeError`](/en/reference/errors/content-collection-invalid-type/))
+There are no longer different types of collections. This must be deleted from your collection definition.
+
+```ts del={8}
+// src/content.config.ts
+import { defineCollection } from 'astro:content';
+import { z } from 'astro/zod';
+import { glob } from 'astro/loaders';
+
+const blog = defineCollection({
+ // For content layer you no longer define a `type`
+ type: 'content',
+ loader: glob({ pattern: '**/[^_]*.{md,mdx}', base: "./src/data/blog" }),
+ schema: z.object({
+ title: z.string(),
+ description: z.string(),
+ pubDate: z.coerce.date(),
+ updatedDate: z.coerce.date().optional(),
+ }),
+});
+```
+
+
+
+legacy collection querying methods `getDataEntryById()` and `getEntryBySlug()` / ([`GetEntryDeprecationError`](/en/reference/errors/get-entry-deprecation-error/))
+Replace both methods with [`getEntry()`](/en/reference/modules/astro-content/#getentry).
+
+
+
+
+legacy collection querying and rendering methods that depend on a `slug` property / ([`ContentSchemaContainsSlugError`](/en/reference/errors/content-schema-contains-slug-error/))
+Previously, the `id` was based on the filename, and there was a `slug` property that could be used in a URL. Now the [CollectionEntry](/en/reference/modules/astro-content/#collectionentry) `id` is a slug. If you need access to the filename (previously available as the `id`), use the `filePath` property. Replace instances of `slug` with `id`:
+
+```astro ins={6} del={5} title="src/pages/[slug].astro"
+---
+export async function getStaticPaths() {
+ const posts = await getCollection('blog');
+ return posts.map((post) => ({
+ params: { slug: post.slug },
+ params: { slug: post.id },
+ props: post,
+ }));
+}
+---
+```
+
+
+
+content rendered using `entry.render()`
+Collection entries no longer have a `render()` method. Instead, import the `render()` function from `astro:content` and use `render(entry)`:
+
+```astro title="src/pages/index.astro" ins=", render" del={6} ins={7}
+---
+import { getEntry, render } from 'astro:content';
+
+const post = await getEntry('pages', 'homepage');
+
+const { Content, headings } = await post.render();
+const { Content, headings } = await render(post);
+---
+
+```
+
+
+
+ See [the Astro v5 upgrade guide](/en/guides/upgrade-to/v5/#legacy-v20-content-collections-api) for previous guidance about backwards compatibility of legacy collections in Astro v5 and full step-by-step instructions for upgrading legacy collections to the new Content Layer API.
+
+### Removed: ` ` component
+
+
+
+In Astro 5.0, the ` ` component was renamed to ` ` to clarify the role of the component. The new name makes it more clear that the features you get from Astro's ` ` routing component are slightly different from the native CSS-based MPA router. However, a deprecated version of the ` ` component still existed and may have functioned in Astro 5.x.
+
+Astro 6.0 removes the ` ` component entirely and it can no longer be used in your project. Update to the ` ` component to continue to use these features.
+
+#### What should I do?
+
+Replace all occurrences of the `ViewTransitions` import and component with `ClientRouter`:
+
+```astro title="src/layouts/MyLayout.astro" del={1,7} ins={2,8}
+import { ViewTransitions } from 'astro:transitions';
+import { ClientRouter } from 'astro:transitions';
+
+
+
+ ...
+
+
+
+
+```
+
+Read more about [view transitions and client-side routing in Astro](/en/guides/view-transitions/).
+
+### Removed: `emitESMImage()`
+
+
+
+In Astro 5.6.2, the `emitESMImage()` function was deprecated in favor of `emitImageMetadata()`, which removes two deprecated arguments that were not meant to be exposed for public use: `_watchMode` and `experimentalSvgEnabled`.
+
+Astro 6.0 removes `emitESMImage()` entirely. Update to `emitImageMetadata()` to keep your current behavior.
+
+#### What should I do?
+
+Replace all occurrences of the `emitESMImage()` with `emitImageMetadata()` and remove unused arguments:
+
+```ts del={1,5} ins={2,6}
+import { emitESMImage } from 'astro/assets/utils';
+import { emitImageMetadata } from 'astro/assets/utils';
+
+const imageId = '/images/photo.jpg';
+const result = await emitESMImage(imageId, false, false);
+const result = await emitImageMetadata(imageId);
+```
+
+Read more about [`emitImageMetadata()`](/en/reference/modules/astro-assets/#emitimagemetadata).
+
+### Removed: `Astro.glob()`
+
+
+
+In Astro 5.0, `Astro.glob()` was deprecated in favor of using `getCollection()` to query your collections, and `import.meta.glob()` to query other source files in your project.
+
+Astro 6.0 removes `Astro.glob()` entirely. Update to `import.meta.glob()` to keep your current behavior.
+
+#### What should I do?
+
+Replace all use of `Astro.glob()` with `import.meta.glob()`. Note that `import.meta.glob()` no longer returns a `Promise`, so you may have to update your code accordingly. You should not require any updates to your [glob patterns](/en/guides/imports/#glob-patterns).
+
+```astro title="src/pages/blog.astro" del={2} ins={3}
+---
+const posts = await Astro.glob('./posts/*.md');
+const posts = Object.values(import.meta.glob('./posts/*.md', { eager: true }));
+---
+
+{posts.map((post) => {post.frontmatter.title} )}
+```
+
+Where appropriate, consider using [content collections](/en/guides/content-collections/) to organize your content, which has its own newer, more performant querying functions.
+
+You may also wish to consider using glob packages from NPM, such as [`fast-glob`](https://www.npmjs.com/package/fast-glob).
+
+Learn more about [importing files with `import.meta.glob`](/en/guides/imports/#importmetaglob).
+
+### Removed: exposed `astro:actions` internals
+
+
+
+In Astro 5.x, some internals were exported from `astro:actions` that were not meant to be exposed for public use.
+
+Astro 6.0 removes the following functions, classes and types as exports from the `astro:actions` virtual module. These can no longer be imported in your project files:
+
+- `ACTION_ERROR_CODES`
+- `ActionInputError`
+- `appendForwardSlash`
+- `astroCalledServerError`
+- `callSafely`
+- `deserializeActionResult`
+- `formDataToObject`
+- `getActionQueryString`
+- `serializeActionResult`
+- `type Actions`
+- `type ActionAccept`
+- `type AstroActionContext`
+- `type SerializedActionResult`
+
+#### What should I do?
+
+Replace all imports of `serializeActionResult()` and `deserializeActionResult()` with `getActionContext()`. These two methods are now available through `getActionContext()`:
+
+```ts title="src/middleware.ts" del={2} ins={3,6}
+import { defineMiddleware } from 'astro:middleware';
+import { serializeActionResult, deserializeActionResult } from 'astro:actions';
+import { getActionContext } from 'astro:actions';
+
+export const onRequest = defineMiddleware(async (context, next) => {
+ const { serializeActionResult, deserializeActionResult } = getActionContext(context);
+ // ...
+});
+```
+
+Remove any occurrences of the other removed exports:
+
+```ts del={1-13}
+import {
+ ACTION_ERROR_CODES,
+ ActionInputError,
+ appendForwardSlash,
+ astroCalledServerError,
+ callSafely,
+ formDataToObject,
+ getActionQueryString,
+ type Actions,
+ type ActionAccept,
+ type AstroActionContext,
+ type SerializedActionResult,
+} from 'astro:actions';
+```
+
+Learn more about all utilities available in the [Actions API Reference](/en/reference/modules/astro-actions/).
+
+### Removed: Percent-Encoding in routes
+
+
+
+In Astro 5.x, it was possible to include a percent-encoded percent sign (`%25`) in filenames.
+
+Astro 6.0 removes support for the characters `%25` in filenames for security reasons. This restriction prevents encoding-based security bypasses where `%25` decodes to `%`, potentially leading to ambiguous or invalid encoding sequences.
+
+#### What should I do?
+
+If you have route files with `%25` in the filename, rename them to use a different character:
+
+```bash del={1} ins={2}
+src/pages/test%25file.astro
+src/pages/test-file.astro
+```
+
+### Removed: `astro:ssr-manifest` virtual module (Integration API)
+
+
+
+In Astro 5.x, the deprecated `astro:ssr-manifest` virtual module could still be used to access configuration values.
+
+Astro 6.0 removes the `astro:ssr-manifest` virtual module entirely. It is no longer used by integrations or internally by Astro. The manifest is now passed directly through integration hooks and adapter APIs rather than through a virtual module. For build-specific manifest data, use the `astro:build:ssr` integration hook, which receives the manifest as a parameter.
+
+#### What should I do?
+
+If your integration or code imports from `astro:ssr-manifest`, use `astro:config/server` instead to access configuration values:
+
+```ts del={1} ins={2,3}
+import { manifest } from 'astro:ssr-manifest';
+import { srcDir, outDir, root } from 'astro:config/server';
+// Use srcDir, outDir, root, etc. for configuration values
+```
+
+Learn more about [the `astro:config` virtual module](/en/reference/modules/astro-config/).
+
+### Removed: `RouteData.generate()` (Adapter API)
+
+
+
+In Astro 5.x, routes could be generated using the `generate()` method on `RouteData`.
+
+Astro 6.0 removes `RouteData.generate()` because route generation is now handled internally by Astro.
+
+#### What should I do?
+
+Remove any calls to `route.generate()` in your code. This method is no longer needed:
+
+```ts del={1}
+const generated = route.generate(params);
+```
+
+Learn more about [the Adapter API](/en/reference/adapter-reference/).
+
+### Removed: `routes` on `astro:build:done` hook (Integration API)
+
+
+
+In Astro 5.0, accessing `routes` on the `astro:build:done` hook was deprecated.
+
+Astro 6.0 removes the `routes` array passed to this hook entirely. Instead, the `astro:routes:resolved` hook should be used.
+
+#### What should I do?
+
+Remove any instance of `routes` passed to `astro:build:done` and replace it with the new `astro:routes:resolved` hook. Access `distURL` on the newly exposed `assets` map:
+
+```js title="my-integration.mjs" ins={2,6-8,11,13-18} del={10}
+const integration = () => {
+ let routes
+ return {
+ name: 'my-integration',
+ hooks: {
+ 'astro:routes:resolved': (params) => {
+ routes = params.routes
+ },
+ 'astro:build:done': ({
+ routes
+ assets
+ }) => {
+ for (const route of routes) {
+ const distURL = assets.get(route.pattern)
+ if (distURL) {
+ Object.assign(route, { distURL })
+ }
+ }
+ console.log(routes)
+ }
+ }
+ }
+}
+```
+
+Learn more about [the Integration API `astro:routes:resolved` hook](/en/reference/integrations-reference/#astroroutesresolved) for building integrations.
+
+### Removed: `entryPoints` on `astro:build:ssr` hook (Integration API)
+
+
+
+In Astro 5.0, [`functionPerRoute` was deprecated](/en/guides/upgrade-to/v5/#deprecated-functionperroute-adapter-api). That meant that `entryPoints` on the `astro:build:ssr` hook was always empty.
+
+Astro 6.0 removes the `entryPoints` map passed to this hook entirely.
+
+#### What should I do?
+
+Remove any instance of `entryPoints` passed to `astro:build:ssr`:
+
+```js title="my-integration.mjs" del={6}
+const integration = () => {
+ return {
+ name: 'my-integration',
+ hooks: {
+ 'astro:build:ssr': (params) => {
+ someLogic(params.entryPoints)
+ },
+ }
+ }
+}
+```
+
+### Removed: old `app.render()` signature (Adapter API)
+
+
+
+In Astro 4.0, the `app.render()` signature that allowed passing `routeData` and `locals` as optional arguments was deprecated in favor of a single optional `renderOptions` argument.
+
+Astro 6.0 removes this signature entirely. Attempting to pass these separate arguments will now cause an error in your project.
+
+#### What should I do?
+
+Review your `app.render` calls and pass `routeData` and `locals` as properties of an object instead of as multiple independent arguments:
+
+```ts title="my-adapter/entrypoint.ts" del={1} ins={2}
+app.render(request, routeData, locals)
+app.render(request, { routeData, locals })
+```
+
+Learn more about the [Adapter API](/en/reference/adapter-reference/).
+
+### Removed: `app.setManifestData()` (Adapter API)
+
+
+
+In Astro 5.0, the `app.setManifestData()` method was available on `App` and `NodeApp`, but is no longer used nor needed.
+
+Astro 6.0 removes this method entirely.
+
+#### What should I do?
+
+Remove any call to `app.setManifestData()`. If you need to update the manifest, create a new `App` instance.
+
+Learn more about the [Adapter API](/en/reference/adapter-reference/).
+
+### Removed: `handleForms` prop for the ` ` component
+
+
+
+In Astro 4.0, the `handleForms` prop of the ` ` component was deprecated, as it was no longer necessary to opt in to handling `submit` events for `form` elements. This functionality has been built in by default and the property, if still included in your project, silently had no impact on form submission.
+
+Astro 6.0 removes this prop entirely and it now must be removed to avoid errors in your project.
+
+#### What should I do?
+
+Remove the `handleForms` property from your ` ` component if it exists. It has provided no additional functionality, and so removing it should not change any behavior in your project:
+
+```astro title="src/pages/index.astro" del="handleForms"
+---
+import { ClientRouter } from "astro:transitions";
+---
+
+
+
+
+
+
+
+
+```
+
+Learn more about [transitions with forms](/en/guides/view-transitions/#transitions-with-forms).
+
+### Removed: `prefetch()` `with` option
+
+
+
+In Astro 4.8.4, the `with` option of the programmatic `prefetch()` function was deprecated in favor of a more sensible default behavior that no longer required specifying the priority of prefetching for each page.
+
+Astro 6.0 removes this option entirely and it is no longer possible to configure the priority of prefetching by passing the `with` option. Attempting to do so will now cause errors.
+
+By default, Astro's prefetching now uses an automatic approach that will always try to use `
+
+In Astro 5.5.6, the `ActionAPIContext.rewrite` method was deprecated because custom endpoints should be used instead of rewrites.
+
+Astro 6.0 removes the `rewrite()` method from `ActionAPIContext` entirely and it may no longer be used.
+
+#### What should I do?
+
+Review your Actions handlers and remove any call to `rewrite()`:
+
+
+```ts title="src/actions/index.ts" del={10}
+import { defineAction } from 'astro:actions';
+import { z } from 'astro/zod';
+
+export const server = {
+ getGreeting: defineAction({
+ input: z.object({
+ // ...
+ }),
+ handler: async (input, context) => {
+ context.rewrite('/')
+ // ...
+ }
+ })
+}
+```
+
+Learn more about [rewrites](/en/guides/routing/#rewrites).
+
+### Removed: schema function signature (Content Loader API)
+
+
+
+In Astro 5.x, a content loader could choose to define a schema as a function instead of defining a Zod schema object for validation. This is useful to dynamically generate the schema based on the configuration options or by introspecting an API.
+
+Astro 6.0 removes this signature and introduces a new `createSchema()` property as a replacement for those who still want to dynamically define a schema in their content loader.
+
+Providing a schema function in the old way will log a warning message that the loader's schema is being ignored, but otherwise the loader will continue to work as if no schema had been provided. In a future major version, loaders that provide a schema function will throw an error and cannot be used.
+
+#### What should I do?
+
+If you are building a content loader and using a function to dynamically return a collection `schema` property, you must remove your existing function and use the new `createSchema()` property to define your schema instead.
+
+For example, you can reproduce Astro's previous behavior by using `zod-to-ts` directly with `createSchema()` and any previous function logic:
+
+```ts del={11} ins={2,12-22}
+import type { Loader } from 'astro/loaders'
+import { createTypeAlias, zodToTs } from 'zod-to-ts'
+import { getSchemaFromApi } from './utils'
+
+function myLoader() {
+ return {
+ name: 'my-loader',
+ load: async (context) => {
+ // ...
+ },
+ schema: async () => await getSchemaFromApi(),
+ createSchema: async () => {
+ const schema = await getSchemaFromApi()
+ const identifier = 'Entry'
+ const { node } = zodToTs(schema, identifier)
+ const typeAlias = createTypeAlias(node, identifier)
+
+ return {
+ schema,
+ types: `export ${typeAlias}`
+ }
+ }
+ } satisfies Loader
+}
+```
+
+Learn more about [`createSchema()`](/en/reference/content-loader-reference/#createschema) in the Content Loader API reference.
+
+### Removed: session `test` driver
+
+
+
+In Astro 5.x, the internal session `test` driver was exported in the Astro config types, but it was not meant to be exposed for public use.
+
+Astro 6.0 removes the session `test` driver as it is no longer used internally to test `context.session`.
+
+#### What should I do?
+
+It is unlikely that you are using this internal API. If you do, you must remove any usage of the session `test` driver:
+
+```js title="astro.config.mjs" del={2,6-9}
+import { defineConfig } from 'astro/config'
+import { createMockStorage } from './utils'
+
+export default defineConfig({
+ session: {
+ driver: 'test',
+ options: {
+ mockStorage: createMockStorage()
+ }
+ }
+})
+```
+
+Learn more about the [Session Driver API](/en/reference/session-driver-reference/).
+
+### Removed: support for CommonJS config files
+
+
+
+In Astro 5.x, the Astro config file could use any of the following extensions: `.mjs`, `.js`, `.ts`, `.mts`, `.cjs` and `.cts`.
+
+Astro 6.0 removes `.cjs` and `.cts` extensions.
+
+#### What should I do?
+
+If you have a `astro.config.cjs` or `astro.config.cts` file, update it to use of the supported extensions: `.mjs`, `.js`, `.ts` or `.mts`.
+
+Learn more about the [Astro config file](/en/guides/configuring-astro/#the-astro-config-file).
+
+### Experimental Flags
+
+Experimental flags allow you to opt in to features while they are in early development. Astro may also use experimental flags to test breaking changes to default behavior. The following experimental flags have been removed in Astro 6.0 and are now stable, or the new default behavior.
+
+Remove these experimental flags from your Astro config if you were previously using them:
+
+```js del={5-9} title="astro.config.mjs"
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ experimental: {
+ liveContentCollections: true,
+ preserveScriptOrder: true,
+ staticImportMetaEnv: true,
+ headingIdCompat: true,
+ failOnPrerenderConflict: true
+ },
+})
+```
+
+#### Experimental features now stable:
+
+- `liveContentCollections` (See the updated [content collections docs](/en/guides/content-collections/) to learn more about live collections.)
+- `failOnPrerenderConflict` (See the new [`prerenderConflictBehavior`](/en/reference/configuration-reference/#prerenderconflictbehavior) configuration option.)
+
+#### New default or recommended behavior:
+
+- `preserveScriptOrder` (See below for breaking changes to [default `
+
+```
+
+Read more about [using `script`](/en/guides/client-side-scripts/) and [`style`](/en/guides/styling/) tags.
+
+## Breaking Changes
+
+The following changes are considered breaking changes in Astro v6.0. Breaking changes may or may not provide temporary backwards compatibility. If you were using these features, you may have to update your code as recommended in each entry.
+
+### Changed: endpoints with a file extension cannot be accessed with a trailing slash
+
+
+
+In Astro v5.0, custom endpoints whose URL ended in a file extension (e.g. `/src/pages/sitemap.xml.ts` ) could be accessed with a trailing slash (`/sitemap.xml/`) or without (`/sitemap.xml`), regardless of the value configured for `build.trailingSlash`.
+
+In Astro v6.0, these endpoints can only be accessed without a trailing slash. This is true regardless of your `build.trailingSlash` configuration.
+
+#### What should I do?
+
+Review your links to your custom endpoints that include a file extension in the URL and remove any trailing slashes:
+
+```html del={1} ins={2} title="src/pages/index.astro"
+Sitemap
+Sitemap
+```
+
+Learn more about [custom endpoints](/en/guides/endpoints/).
+
+### Changed: `import.meta.env` values are always inlined
+
+
+
+In Astro 5.13, the `experimental.staticImportMetaEnv` flag was introduced to update the behavior when accessing `import.meta.env` directly to align with [Vite's handling of environment variables](https://vite.dev/guide/env-and-mode.html#env-variables) and ensures that `import.meta.env` values are always inlined.
+
+In Astro 5.x, non-public environment variables were replaced by a reference to `process.env`. Additionally, Astro could also convert the value type of your environment variables used through `import.meta.env`, which could prevent access to some values such as the strings `"true"` (which was converted to a boolean value), and `"1"` (which was converted to a number).
+
+Astro 6 removes this experimental flag and makes this the new default behavior in Astro: `import.meta.env` values are always inlined and never coerced.
+
+#### What should I do?
+
+If you were previously using this experimental feature, you must [remove this experimental flag from your configuration](#experimental-flags) as it no longer exists.
+
+If you were relying on coercion, you may need to update your project code to apply it manually:
+
+```ts title="src/components/MyComponent.astro" del={1} ins={2}
+const enabled: boolean = import.meta.env.ENABLED;
+const enabled: boolean = import.meta.env.ENABLED === "true";
+```
+
+If you were relying on the transformation into `process.env`, you may need to update your project code to apply it manually:
+
+```ts title="src/components/MyComponent.astro" del={1} ins={2}
+const enabled: boolean = import.meta.env.DB_PASSWORD;
+const enabled: boolean = process.env.DB_PASSWORD;
+```
+
+You may also need to update types:
+
+```ts title="src/env.d.ts" del={3-4} ins={5,12-16}
+interface ImportMetaEnv {
+ readonly PUBLIC_POKEAPI: string;
+ readonly DB_PASSWORD: string;
+ readonly ENABLED: boolean;
+ readonly ENABLED: string;
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
+
+namespace NodeJS {
+ interface ProcessEnv {
+ DB_PASSWORD: string;
+ }
+}
+```
+
+If you need more control over environment variables in Astro, we recommend you use `astro:env`.
+
+Learn more about [environment variables](/en/guides/environment-variables/) in Astro, including `astro:env`.
+
+### Changed: Cropping by default in default image service
+
+
+
+In Astro 5.0, the default image service would only apply cropping when the `fit` option was provided.
+
+Astro 6.0 applies cropping by default without requiring setting the `fit` option.
+
+#### What should I do?
+
+No changes are needed to your existing cropped images as the `fit` property is still valid. However, if you were previously setting `fit` to `contain` (its default value) in order to crop your images, you may now remove this option and still achieve the same cropping behavior by specifying `width` and `height` alone:
+
+```ts title="src/components/MyImage.astro" del={5} ins={6}
+---
+import { Image } from 'astro:assets';
+import myImage from '../assets/photo.jpg';
+---
+
+
+```
+
+### Changed: Never upscale images in default image service
+
+
+
+In Astro 5.0, the default image service would upscale images when the requested dimensions were larger than the source image.
+
+Astro 6.0 removes this behavior: the default image service never upscales images.
+
+#### What should I do?
+
+Review your images and update dimensions as needed. If you do need to upscale images, you may consider upscaling the images manually or using a custom image service that supports upscaling.
+
+### Changed: Markdown heading ID generation
+
+
+
+In Astro 5.x, an additional default processing step to Markdown stripped trailing hyphens from the end of IDs for section headings ending in special characters. This provided a cleaner `id` value, but could lead to incompatibilities rendering your Markdown across platforms.
+
+In Astro 5.5, the `experimental.headingIdCompat` flag was introduced to allow you to make the IDs generated by Astro for Markdown headings compatible with common platforms like GitHub and npm, using the popular [`github-slugger`](https://github.com/Flet/github-slugger) package.
+
+Astro 6.0 removes this experimental flag and makes this the new default behavior in Astro: trailing hyphens from the end of IDs for headings ending in special characters are no longer removed.
+
+#### What should I do?
+
+If you have manual links to headings, you may need to update the anchor link value with a new trailing hyphen. For example, the following Markdown heading:
+
+```md
+## ` `
+```
+
+will now generate the following HTML with a trailing hyphen in the heading `id`:
+
+```html ins="-"
+<Picture />
+```
+
+and must now be linked to as:
+
+```markdown ins="-"
+See [the Picture component](/en/guides/images/#picture-) for more details.
+```
+
+If you were previously using the experimental feature to enforce trailing hyphens, you must [remove this experimental flag from your configuration](#experimental-flags) as it no longer exists.
+
+If you were previously using the `rehypeHeadingIds` plugin directly to enforce compatibility, remove the `headingIdCompat` option as it no longer exists:
+
+```js title="astro.config.mjs" del={8} ins={9}
+import { defineConfig } from 'astro/config';
+import { rehypeHeadingIds } from '@astrojs/markdown-remark';
+import { otherPluginThatReliesOnHeadingIDs } from 'some/plugin/source';
+
+export default defineConfig({
+ markdown: {
+ rehypePlugins: [
+ [rehypeHeadingIds, { headingIdCompat: true }],
+ [rehypeHeadingIds],
+ otherPluginThatReliesOnHeadingIDs,
+ ],
+ },
+});
+```
+
+If you want to keep the old ID generation for backward compatibility reasons, you can create a custom rehype plugin that will generate headings IDs like Astro 5.x. This will allow you to continue to use your existing anchor links without adding trailing hyphens.
+
+
+
+Create a custom rehype plugin to strip trailing hyphens
+
+
+
+1. Install required dependencies:
+
+
+
+ ```sh
+ npm i github-slugger hast-util-heading-rank unist-util-visit hast-util-to-string
+ ```
+
+
+ ```sh
+ pnpm add github-slugger hast-util-heading-rank unist-util-visit hast-util-to-string
+ ```
+
+
+ ```sh
+ yarn add github-slugger hast-util-heading-rank unist-util-visit hast-util-to-string
+ ```
+
+
+
+2. Create a custom rehype plugin that will generate headings IDs like Astro v5:
+
+ ```js title="plugins/rehype-slug.mjs"
+ import GithubSlugger from 'github-slugger';
+ import { headingRank } from 'hast-util-heading-rank';
+ import { visit } from 'unist-util-visit';
+ import { toString } from 'hast-util-to-string';
+
+ const slugs = new GithubSlugger();
+
+ export function rehypeSlug() {
+ /**
+ * @param {import('hast').Root} tree
+ */
+ return (tree) => {
+ slugs.reset();
+ visit(tree, 'element', (node) => {
+ if (headingRank(node) && !node.properties.id) {
+ let slug = slugs.slug(toString(node));
+ // Strip trailing hyphens like in Astro v5 and below:
+ if (slug.endsWith('-')) slug = slug.slice(0, -1);
+ node.properties.id = slug;
+ }
+ });
+ };
+ }
+ ```
+
+3. Add the custom plugin to your Markdown configuration in `astro.config.mjs`:
+
+ ```js title="astro.config.mjs" ins={2} ins="rehypeSlug"
+ import { defineConfig } from 'astro/config';
+ import { rehypeSlug } from './plugins/rehype-slug';
+
+ export default defineConfig({
+ markdown: {
+ rehypePlugins: [rehypeSlug],
+ },
+ });
+ ```
+
+
+
+
+
+Learn more about [Heading IDs](/en/guides/markdown-content/#heading-ids).
+
+### Changed: `getStaticPaths()` cannot return `params` of type number
+
+
+
+In Astro 5.x, `getStaticPaths()` could return `params` of type number, which would always be stringified by Astro. However, that could be confusing because it conflicted with `Astro.params` types.
+
+Astro 6.0 removes this behavior: `getStaticPaths()` must now return string or undefined `params` values.
+
+#### What should I do?
+
+Review your dynamic routes using `getStaticPaths()` and convert any number params to strings:
+
+```astro title="src/pages/post/[id]/[label].astro" del={6,13} ins={7,14}
+---
+export function getStaticPaths() {
+ return [
+ {
+ params: {
+ id: 1,
+ id: "1",
+ label: "foo",
+ }
+ },
+ {
+ params: {
+ id: 2,
+ id: "2",
+ label: "bar",
+ }
+ },
+ ]
+}
+---
+```
+
+Learn more about [dynamic SSG routes with `getStaticPaths()`](/en/guides/routing/#static-ssg-mode).
+
+### Changed: Astro components cannot be rendered in Vitest client environments (Container API)
+
+
+
+In Astro 5.x, rendering an Astro component on the client was forbidden. However we temporarily allowed this behavoir in Vitest client environments such as `jsdom` or `happy-dom` using the [experimental Container API](/en/reference/container-reference/).
+
+Astro 6.0 removes the ability to render Astro components in Vitest client environments: tests that render Astro components must now run in a server environment like `node`.
+
+#### What should I do?
+
+If you use Vitest to run tests that render Astro components in client environments like `jsdom` or `happy-dom`, update your Vitest config to use the `node` environment for these:
+```ts title="vitest.config.ts" del={5} ins={6}
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ environment: 'jsdom',
+ environment: 'node',
+ },
+});
+```
+
+Learn more about [testing Astro components](/en/guides/testing/).
+
+### Changed: Integration hooks and HMR access patterns (Integration API)
+
+
+
+In Astro 5.x, Astro relied on certain patterns for integration hooks and HMR access that were incompatible with or could be improved by integrating Vite's Environment API.
+
+Astro 6.0 uses Vite's new Environment API for build configuration and dev server interactions. This primarily enables dev mode in runtimes like workerd, but means that some integration hooks and HMR access patterns have changed.
+
+#### What should I do?
+
+**For integrations using `astro:build:setup`:**
+
+The hook is now called once with all environments configured (`ssr`, `client`, `prerender`), instead of being called separately for each build target. Remove the `target` parameter and use `vite.environments` to configure specific environments:
+
+```ts title="my-integration.mjs" del={3-7} ins={8-10}
+{
+ hooks: {
+ 'astro:build:setup': ({ target, vite }) => {
+ if (target === 'client') {
+ vite.build.minify = false;
+ }
+ }
+ 'astro:build:setup': ({ vite }) => {
+ vite.environments.client.build.minify = false;
+ }
+ }
+}
+```
+
+**For dev toolbar and integration code accessing HMR:**
+
+Replace `server.hot.send()` with `server.environments.client.hot.send()`:
+
+```ts del={1} ins={2}
+server.hot.send(event)
+server.environments.client.hot.send(event)
+```
+
+Learn more about the [Vite Environment API](https://vite.dev/guide/api-environment) and Astro [integration hooks](/en/reference/integrations-reference/#astrobuildsetup).
+
+### Changed: `SSRManifest` interface structure (Adapter API)
+
+
+
+In Astro 5.x, path properties of the `SSRManifest` interface like `srcDir`, `outDir`, `cacheDir`, `publicDir`, `buildClientDir`, and `buildServerDir` were URL strings.
+
+Astro 6.0 changes the form of these path properties to `URL` objects instead of URL strings. With this change, several new properties are now available on the manifest, and others have been updated or removed.
+
+#### What should I do?
+
+If you were treating these path properties as strings, you will now need to handle the `URL` object. For example, you will now need to access the `href` property of the `URL` object:
+
+```ts del={2} ins={3}
+// To retrieve the same format (e.g., "file:///path/to/src"), make the following change:
+const srcPath = manifest.srcDir;
+const srcPath = manifest.srcDir.href;
+```
+
+If you were accessing the `hrefRoot` property, you will need to remove it, as it is no longer available on the manifest.
+
+Update any use of `serverIslandMappings` and `sessionDriver`. These are now async methods:
+
+```ts del={1,2} ins={3,4}
+const mappings = manifest.serverIslandMappings;
+const driver = manifest.sessionDriver;
+const mappings = await manifest.serverIslandMappings?.();
+const driver = await manifest.sessionDriver?.();
+```
+
+Learn more about [the Adapter API](/en/reference/adapter-reference/).
+### Changed: schema types are inferred instead of generated (Content Loader API)
+
+
+
+In Astro 5.x, the types for content collections were generated using `zod-to-ts` when provided by a content loader and not defined by a user-provided schema.
+
+Astro 6.0 removes this behavior: types are no longer generated using `zod-to-ts`. Instead, types are inferred.
+
+#### What should I do?
+
+If you are providing a `schema` in a content loader, you must use the [TypeScript' `satisfies` operator](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator):
+
+```ts del={3,11} ins={4,12}
+import type { Loader } from 'astro/loaders'
+
+function myLoader(): Loader {
+function myLoader() {
+ return {
+ name: 'my-loader',
+ load: async (context) => {
+ // ...
+ },
+ schema: z.object({/* ... */})
+ }
+ } satisfies Loader
+}
+```
+
+Learn more about [defining loader schema types](/en/reference/content-loader-reference/#the-loader-object).
+
+{/*
+## Community Resources
+
+Know a good resource for Astro v6.0? [Edit this page](https://github.com/withastro/docs/edit/main/src/content/docs/en/guides/upgrade-to/v6.mdx) and add a link below!
+*/}
+
+## Known Issues
+
+Please check [Astro's issues on GitHub](https://github.com/withastro/astro/issues/) for any reported issues, or to file an issue yourself.
diff --git a/src/content/docs/en/guides/view-transitions.mdx b/src/content/docs/en/guides/view-transitions.mdx
index fef4267ae5905..0f30c5ac2fc83 100644
--- a/src/content/docs/en/guides/view-transitions.mdx
+++ b/src/content/docs/en/guides/view-transitions.mdx
@@ -461,7 +461,7 @@ One way to implement this safely is to ensure only a set of known paths can be r
The exact kind of sanitization you need will depend on your site and what you want to allow.
-Consider enabling Astro’s [experimental Content Security Policy feature](/en/reference/experimental-flags/csp/) to help protect against cross-site scripting (XSS) risks if using user input with the `navigate()` API.
+Consider enabling Astro’s [Content Security Policy feature](/en/reference/configuration-reference/#securitycsp) to help protect against cross-site scripting (XSS) risks if using user input with the `navigate()` API.
## Fallback control
diff --git a/src/content/docs/en/install-and-setup.mdx b/src/content/docs/en/install-and-setup.mdx
index d5986b397a2d3..8571d24b98b94 100644
--- a/src/content/docs/en/install-and-setup.mdx
+++ b/src/content/docs/en/install-and-setup.mdx
@@ -21,7 +21,7 @@ Prefer to try Astro in your browser? Visit [astro.new](https://astro.new/) to br
## Prerequisites
-- **Node.js** - `v18.20.8` or `v20.3.0`, `v22.0.0` or higher. (`v19` and `v21` are not supported.)
+- **Node.js** - `v22.12.0` or higher. Odd-numbered versions like `v23` are not supported.
- **Text editor** - We recommend [VS Code](https://code.visualstudio.com/) with our [Official Astro extension](https://marketplace.visualstudio.com/items?itemName=astro-build.astro-vscode).
- **Terminal** - Astro is accessed through its command-line interface (CLI).
diff --git a/src/content/docs/en/reference/adapter-reference.mdx b/src/content/docs/en/reference/adapter-reference.mdx
index 7ad70ddc446cb..5e8bdbbec380b 100644
--- a/src/content/docs/en/reference/adapter-reference.mdx
+++ b/src/content/docs/en/reference/adapter-reference.mdx
@@ -246,6 +246,49 @@ export default function createIntegration() {
}
```
+### `entryType`
+
+
+
+**Type:** `"legacy-dynamic" | "self"`
+**Default**: `"legacy-dynamic"`
+
+
+
+Specifies whether the adapter's entrypoint is automatically created by Astro (default), or whether a custom entrypoint is used.
+
+To provide your own entrypoint, configure `entryType: "self"` and set [`rollupOptions.input`](https://rollupjs.org/configuration-options/#input) with your custom entrypoint path.
+
+The following example defines the `entryType` and Rollup options to tell Astro that a custom entrypoint is provided:
+
+```js title="my-adapter.mjs" {9-11,20}
+export default function createIntegration() {
+ return {
+ name: '@example/my-adapter',
+ hooks: {
+ 'astro:config:setup': ({ updateConfig }) => {
+ updateConfig({
+ vite: {
+ build: {
+ rollupOptions: {
+ input: "@example/my-adapter/custom-entrypoint.js"
+ }
+ }
+ }
+ })
+ },
+ 'astro:config:done': ({ setAdapter }) => {
+ setAdapter({
+ name: '@example/my-adapter',
+ serverEntrypoint: '@example/my-adapter/server.js',
+ entryType: "self",
+ });
+ },
+ },
+ };
+}
+```
+
## Building a server entrypoint
You will need to create a file that executes during server-side requests to enable on-demand rendering with your particular host. Astro's adapter API attempts to work with any type of host and gives a flexible way to conform to the host APIs.
@@ -1102,7 +1145,7 @@ export default function createIntegration() {
}
```
-The value of the headers might change based on the features enabled/used by the application. For example, if [CSP is enabled](/en/reference/experimental-flags/csp/), the ` ` element is not added to the static page. Instead, its `content` is available in the `experimentalRouteToHeaders` map.
+The value of the headers might change based on the features enabled/used by the application. For example, if [CSP is enabled](/en/reference/configuration-reference/#securitycsp), the ` ` element is not added to the static page. Instead, its `content` is available in the `experimentalRouteToHeaders` map.
## Adapter types reference
diff --git a/src/content/docs/en/reference/api-reference.mdx b/src/content/docs/en/reference/api-reference.mdx
index 8bcdbedcee4bb..1f00246f1e2d3 100644
--- a/src/content/docs/en/reference/api-reference.mdx
+++ b/src/content/docs/en/reference/api-reference.mdx
@@ -1049,117 +1049,161 @@ Loads a session by ID. In normal use, a session is loaded automatically from the
+### `csp`
-### Deprecated object properties
-#### `Astro.glob()`
+
-:::caution[Deprecated in v5.0]
-Use [Vite's `import.meta.glob`](https://vite.dev/guide/features.html#glob-import) to query project files.
+**Type**: `object | undefined`
+
+
-`Astro.glob('../pages/post/*.md')` can be replaced with:
+Astro's CSP runtime APIs enable support for [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP) to help minimize certain types of security threats by controlling which resources a document is allowed to load. This provides additional protection against [cross-site scripting (XSS)](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting) attacks.
-`Object.values(import.meta.glob('../pages/post/*.md', { eager: true }));`
+You can customize the ` ` element per page from the `Astro` global inside `.astro` components, or the `APIContext` type in endpoints and middleware.
-See the [imports guide](/en/guides/imports/#importmetaglob) for more information and usage.
-:::
+When resources are inserted multiple times or from multiple sources (e.g. defined in your [`csp` config](/en/reference/configuration-reference/#securitycsp) and added using the following CSP runtime APIs, Astro will merge and deduplicate all resources to create your ` ` element.
+
+
+#### `insertDirective`
+
+
+
+**Type:** `(directive: CspDirective) => void`
+
+
-`Astro.glob()` is a way to load many local files into your static site setup.
+Adds a single directive to the current page. You can call this method multiple times to add additional directives.
-```astro
+```astro title="src/pages/index.astro"
---
-// src/components/my-component.astro
-const posts = await Astro.glob('../pages/post/*.md'); // returns an array of posts that live at ./src/pages/post/*.md
+Astro.csp?.insertDirective("default-src 'self'");
+Astro.csp?.insertDirective("img-src 'self' https://images.cdn.example.com");
---
+```
-
-{posts.slice(0, 3).map((post) => (
-
- {post.frontmatter.title}
- {post.frontmatter.description}
- Read more
-
-))}
-
+After the build, the ` ` element for this individual page will incorporate your additional directives alongside the existing `script-src` and `style-src` directives:
+
+```html
+
```
-`.glob()` only takes one parameter: a relative URL glob of which local files you'd like to import. It’s asynchronous and returns an array of the exports from matching files.
+#### `insertStyleResource`
-`.glob()` can't take variables or strings that interpolate them, as they aren't statically analyzable. (See [the imports guide](/en/guides/imports/#supported-values) for a workaround.) This is because `Astro.glob()` is a wrapper of Vite's [`import.meta.glob()`](https://vite.dev/guide/features.html#glob-import).
+
-:::note
-You can also use `import.meta.glob()` itself in your Astro project. You may want to do this when:
-- You need this feature in a file that isn't `.astro`, like an API route. `Astro.glob()` is only available in `.astro` files, while `import.meta.glob()` is available anywhere in the project.
-- You don't want to load each file immediately. `import.meta.glob()` can return functions that import the file content, rather than returning the content itself. Note that this import includes all styles and scripts for any imported files. These will be bundled and added to the page whether or not a file is actually used, as this is decided by static analysis, not at runtime.
-- You want access to each file's path. `import.meta.glob()` returns a map of a file's path to its content, while `Astro.glob()` returns a list of content.
-- You want to pass multiple patterns; for example, you want to add a "negative pattern" that filters out certain files. `import.meta.glob()` can optionally take an array of glob strings, rather than a single string.
+**Type:** `(resource: string) => void`
+
+
-Read more in the [Vite documentation](https://vite.dev/guide/features.html#glob-import).
-:::
+Inserts a new resource to be used for the `style-src` directive.
-##### Markdown Files
-
-Markdown files loaded with `Astro.glob()` return the following `MarkdownInstance` interface:
-
-```ts
-export interface MarkdownInstance> {
- /* Any data specified in this file's YAML/TOML frontmatter */
- frontmatter: T;
- /* The absolute file path of this file */
- file: string;
- /* The rendered path of this file */
- url: string | undefined;
- /* Astro Component that renders the contents of this file */
- Content: AstroComponentFactory;
- /** (Markdown only) Raw Markdown file content, excluding layout HTML and YAML/TOML frontmatter */
- rawContent(): string;
- /** (Markdown only) Markdown file compiled to HTML, excluding layout HTML */
- compiledContent(): string;
- /* Function that returns an array of the h1...h6 elements in this file */
- getHeadings(): Promise<{ depth: number; slug: string; text: string }[]>;
- default: AstroComponentFactory;
-}
+```astro title="src/pages/index.astro"
+---
+Astro.csp?.insertStyleResource("https://styles.cdn.example.com");
+---
+```
+
+After the build, the ` ` element for this individual page will add your source to the default `style-src` directive:
+
+```html
+
```
-You can optionally provide a type for the `frontmatter` variable using a TypeScript generic.
+#### `insertStyleHash`
+
+
+
+**Type:** `(hash: CspHash) => void`
+
+
+
+Adds a new hash to the `style-src` directive.
-```astro
+```astro title="src/pages/index.astro"
---
-interface Frontmatter {
- title: string;
- description?: string;
-}
-const posts = await Astro.glob('../pages/post/*.md');
+Astro.csp?.insertStyleHash("sha512-styleHash");
---
+```
+
+After the build, the ` ` element for this individual page will add your hash to the default `style-src` directive:
-
- {posts.map(post => {post.frontmatter.title} )}
-
+```html
+
```
-##### Astro Files
+#### `insertScriptResource`
-Astro files have the following interface:
+
-```ts
-export interface AstroInstance {
- /* The file path of this file */
- file: string;
- /* The URL for this file (if it is in the pages directory) */
- url: string | undefined;
- default: AstroComponentFactory;
-}
+**Type:** `(resource: string) => void`
+
+
+
+Inserts a new valid source to be used for the `script-src` directive.
+
+```astro title="src/pages/index.astro"
+---
+Astro.csp?.insertScriptResource("https://scripts.cdn.example.com");
+---
+```
+
+After the build, the ` ` element for this individual page will add your source to the default `script-src` directive:
+
+```html
+
```
-##### Other Files
+#### `insertScriptHash`
+
+
+
+**Type:** `(hash: CspHash) => void`
+
+
-Other files may have various different interfaces, but `Astro.glob()` accepts a TypeScript generic if you know exactly what an unrecognized file type contains.
+Adds a new hash to the `script-src` directive.
-```ts
+```astro title="src/pages/index.astro"
---
-interface CustomDataFile {
- default: Record;
-}
-const data = await Astro.glob('../data/**/*.js');
+Astro.csp?.insertScriptHash("sha512-scriptHash");
---
```
+
+After the build, the ` ` element for this individual page will add your hash to the default `script-src` directive:
+
+```html
+
+```
diff --git a/src/content/docs/en/reference/cli-reference.mdx b/src/content/docs/en/reference/cli-reference.mdx
index bcf56ecc23dc8..0a0b87b283a9b 100644
--- a/src/content/docs/en/reference/cli-reference.mdx
+++ b/src/content/docs/en/reference/cli-reference.mdx
@@ -420,7 +420,7 @@ astro --config config/astro.config.mjs dev
-Clear the [content layer cache](/en/guides/content-collections/#defining-the-collection-loader), forcing a full rebuild.
+Clear the content layer cache, forcing a full rebuild.
### `--mode `
diff --git a/src/content/docs/en/reference/configuration-reference.mdx b/src/content/docs/en/reference/configuration-reference.mdx
index 4e30098a4ecb4..71dffcd766ea8 100644
--- a/src/content/docs/en/reference/configuration-reference.mdx
+++ b/src/content/docs/en/reference/configuration-reference.mdx
@@ -366,6 +366,59 @@ Using `'class'` is helpful when you want to ensure that element selectors within
Using `'where'` gives you more control over specificity, but requires that you use higher-specificity selectors, layers, and other tools to control which selectors are applied.
Using `'attribute'` is useful when you are manipulating the `class` attribute of elements and need to avoid conflicts between your own styling logic and Astro's application of styles.
+### prerenderConflictBehavior
+
+
+
+**Type:** `'error' | 'warn' | 'ignore'`
+**Default:** `'warn'`
+
+
+
+Determines the default behavior when two routes generate the same prerendered URL:
+- `error`: fail the build and display an error, forcing you to resolve the conflict
+- `warn` (default): log a warning when conflicts occur, but build using the highest-priority route
+- `ignore`: silently build using the highest-priority route when conflicts occur
+
+```js
+{
+ prerenderConflictBehavior: 'error'
+}
+```
+
+### vite
+
+
+
+**Type:** `ViteUserConfig`
+
+
+Pass additional configuration options to Vite. Useful when Astro doesn't support some advanced configuration that you may need.
+
+View the full `vite` configuration object documentation on [vite.dev](https://vite.dev/config/).
+
+#### Examples
+
+```js
+{
+ vite: {
+ ssr: {
+ // Example: Force a broken package to skip SSR processing, if needed
+ external: ['broken-npm-package'],
+ }
+ }
+}
+```
+
+```js
+{
+ vite: {
+ // Example: Add custom vite plugins directly to your Astro project
+ plugins: [myPlugin()],
+ }
+}
+```
+
### security
@@ -447,37 +500,322 @@ The patterns support wildcards for flexible hostname matching:
When not configured, `X-Forwarded-Host` headers are not trusted and will be ignored.
-### vite
+#### security.csp
-**Type:** `ViteUserConfig`
+**Type:** `boolean | object`
+**Default:** `false`
+
-Pass additional configuration options to Vite. Useful when Astro doesn't support some advanced configuration that you may need.
+Enables support for [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP) to help minimize certain types of security threats by controlling which resources a document is allowed to load. This provides additional protection against [cross-site scripting (XSS)](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting) attacks.
-View the full `vite` configuration object documentation on [vite.dev](https://vite.dev/config/).
+Enabling this feature adds additional security to Astro's handling of processed and bundled scripts and styles by default, and allows you to further configure these, and additional, content types.
-#### Examples
+This feature comes with some limitations:
+- External scripts and external styles are not supported out of the box, but you can [provide your own hashes](https://v6.docs.astro.build/en/reference/configuration-reference/#hashes).
+- [Astro's view transitions](https://v6.docs.astro.build/en/guides/view-transitions/) using the ` ` are not supported, but you can [consider migrating to the browser native View Transition API](https://events-3bg.pages.dev/jotter/astro-view-transitions/) instead if you are not using Astro's enhancements to the native View Transitions and Navigation APIs.
+- Shiki isn't currently supported. By design, Shiki functions using inline styles.
-```js
-{
- vite: {
- ssr: {
- // Example: Force a broken package to skip SSR processing, if needed
- external: ['broken-npm-package'],
+:::note
+Due to the nature of the Vite dev server, this feature isn't supported while working in `dev` mode. Instead, you can test this in your Astro project using `build` and `preview`.
+:::
+
+When enabled, Astro will add a ` ` element inside the `` element of each page.
+This element will have the `http-equiv="content-security-policy"` attribute, and the `content` attribute will provide values for the `script-src` and `style-src` [directives](https://v6.docs.astro.build/en/reference/configuration-reference/#securitycspdirectives) based on the script and styles used in the page.
+
+```html
+
+
+
+
+```
+
+You can further customize the ` ` element by enabling this feature with a configuration object that includes additional options.
+
+##### security.csp.algorithm
+
+
+
+**Type:** `"SHA-256" | "SHA-384" | "SHA-512"`
+**Default:** `'SHA-256'`
+
+
+
+The [hash function](https://developer.mozilla.org/en-US/docs/Glossary/Hash_function) to use when generating the hashes of the styles and scripts emitted by Astro.
+
+```js title="astro.config.mjs"
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ security: {
+ csp: {
+ algorithm: 'SHA-512'
}
}
-}
+});
```
-```js
-{
- vite: {
- // Example: Add custom vite plugins directly to your Astro project
- plugins: [myPlugin()],
+##### security.csp.directives
+
+
+
+**Type:** `Array`
+**Default:** `[]`
+
+
+
+A list of [CSP directives](https://content-security-policy.com/#directive) (beyond `script-src` and `style-src` which are included by default) that defines valid sources for specific content types. These directives are added to all pages.
+
+```js title="astro.config.mjs"
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ security: {
+ csp: {
+ directives: [
+ "default-src 'self'",
+ "img-src 'self' https://images.cdn.example.com"
+ ]
+ }
}
-}
+});
+```
+After the build, the ` ` element will add your directives into the `content` value alongside Astro's default directives:
+
+```html
+
+```
+
+##### security.csp.styleDirective
+
+
+
+**Type:** `CspStyleDirective`
+**Default:** `undefined`
+
+
+
+A configuration object that allows you to override the default sources for the `style-src` directive with the [`resources`](https://v6.docs.astro.build/en/reference/configuration-reference/#resources) property, or to provide additional [hashes](https://v6.docs.astro.build/en/reference/configuration-reference#hashes) to be rendered.
+
+###### security.csp.styleDirective.hashes
+
+
+
+**Type:** `Array`
+**Default:** `[]`
+
+
+
+A list of additional hashes to be rendered.
+
+You must provide hashes that start with `sha384-`, `sha512-` or `sha256-`. Other values will cause a validation error. These hashes are added to all pages.
+
+```js title="astro.config.mjs"
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ security: {
+ csp: {
+ styleDirective: {
+ hashes: [
+ "sha384-styleHash",
+ "sha512-styleHash",
+ "sha256-styleHash"
+ ]
+ }
+ }
+ }
+});
+```
+
+After the build, the ` ` element will include your additional hashes in the `style-src` directives:
+
+```html
+
+```
+
+###### security.csp.styleDirective.resources
+
+
+
+**Type:** `Array`
+**Default:** `[]`
+
+
+
+A list of valid sources for `style-src` directives to override Astro's default sources. This will not include `'self'` by default, and must be included in this list if you wish to keep it. These resources are added to all pages.
+
+```js title="astro.config.mjs"
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ security: {
+ csp: {
+ styleDirective: {
+ resources: [
+ "'self'",
+ "https://styles.cdn.example.com"
+ ]
+ }
+ }
+ }
+});
+```
+
+After the build, the ` ` element will instead apply your sources to the `style-src` directives:
+
+```html
+
+
+
+```
+
+When resources are inserted multiple times or from multiple sources (e.g. defined in your `csp` config and added using [the CSP runtime API](/en/reference/api-reference/#csp)), Astro will merge and deduplicate all resources to create your ` ` element.
+
+##### security.csp.scriptDirective
+
+
+
+**Type:** `CspScriptDirective`
+**Default:** `undefined`
+
+
+
+A configuration object that allows you to override the default sources for the `script-src` directive with the [`resources`](https://v6.docs.astro.build/en/reference/configuration-reference/#resources) property, or to provide additional [hashes](https://v6.docs.astro.build/en/reference/configuration-reference#hashes) to be rendered.
+
+###### security.csp.scriptDirective.hashes
+
+
+
+**Type:** `Array`
+**Default:** `[]`
+
+
+
+A list of additional hashes to be rendered.
+
+You must provide hashes that start with `sha384-`, `sha512-` or `sha256-`. Other values will cause a validation error. These hashes are added to all pages.
+
+```js title="astro.config.mjs"
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ security: {
+ csp: {
+ scriptDirective: {
+ hashes: [
+ "sha384-scriptHash",
+ "sha512-scriptHash",
+ "sha256-scriptHash"
+ ]
+ }
+ }
+ }
+});
+```
+
+After the build, the ` ` element will include your additional hashes in the `script-src` directives:
+
+```html
+
+```
+
+###### security.csp.scriptDirective.resources
+
+
+
+**Type:** `Array`
+**Default:** `[]`
+
+
+
+A list of valid sources for the `script-src` directives to override Astro's default sources. This will not include `'self'` by default, and must be included in this list if you wish to keep it. These resources are added to all pages.
+
+```js title="astro.config.mjs"
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ security: {
+ csp: {
+ scriptDirective: {
+ resources: [
+ "'self'", "https://cdn.example.com"
+ ]
+ }
+ }
+ }
+});
+```
+
+After the build, the ` ` element will instead apply your sources to the `script-src` directives:
+
+```html
+
+
+
+```
+
+When resources are inserted multiple times or from multiple sources (e.g. defined in your `csp` config and added using [the CSP runtime API](/en/reference/api-reference/#csp)), Astro will merge and deduplicate all resources to create your ` ` element.
+
+###### security.csp.scriptDirective.strictDynamic
+
+
+
+**Type:** `boolean`
+**Default:** `false`
+
+
+
+Enables [the `strict-dynamic` keyword](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP#the_strict-dynamic_keyword) to support the dynamic injection of scripts.
+
+```js title="astro.config.mjs"
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ security: {
+ csp: {
+ scriptDirective: {
+ strictDynamic: true
+ }
+ }
+ }
+});
```
## Build Options
@@ -851,25 +1189,29 @@ See [the sessions guide](/en/guides/sessions/) for more information.
-**Type:** `string | undefined`
+**Type:** `SessionDriverConfig | undefined`
-The Unstorage driver to use for session storage. The [Node](/en/guides/integrations-guide/node/#sessions),
+The driver to use for session storage. The [Node](/en/guides/integrations-guide/node/#sessions),
[Cloudflare](/en/guides/integrations-guide/cloudflare/#sessions), and
[Netlify](/en/guides/integrations-guide/netlify/#sessions) adapters automatically configure a default driver for you,
but you can specify your own if you would prefer or if you are using an adapter that does not provide one.
-The value is the "Driver name" from the [Unstorage driver documentation](https://unstorage.unjs.io/drivers).
+```js title="astro.config.mjs" ins={7-9} ins=" sessionDrivers "
+import { defineConfig, sessionDrivers } from 'astro/config'
+import vercel from '@astrojs/vercel'
-```js title="astro.config.mjs" ins={4}
-{
- adapter: vercel(),
+export default defineConfig({
+ adapter: vercel()
session: {
- driver: "redis",
- },
-}
+ driver: sessionDrivers.redis({
+ url: process.env.REDIS_URL
+ }),
+ }
+})
```
+
:::note
Some drivers may need extra packages to be installed. Some drivers may also require environment variables or credentials to be set. See the [Unstorage documentation](https://unstorage.unjs.io/drivers) for more information.
:::
@@ -883,6 +1225,10 @@ Some drivers may need extra packages to be installed. Some drivers may also requ
+:::caution[Deprecated]
+This is deprecated and will be removed in a future major version. Instead, pass options to the driver function.
+:::
+
The driver-specific options to use for session storage. The options depend on the driver you are using. See the [Unstorage documentation](https://unstorage.unjs.io/drivers)
for more information on the options available for each driver.
@@ -1587,14 +1933,14 @@ export default defineConfig({
**Type:** `boolean`
-**Default:** `true`
+**Default:** `false`
Configures whether or not the home URL (`/`) generated by `src/pages/index.astro`
will redirect to `/[defaultLocale]` when `prefixDefaultLocale: true` is set.
-Set `redirectToDefaultLocale: false` to disable this automatic redirection at the root of your site:
+Set `redirectToDefaultLocale: true` to enable this automatic redirection at the root of your site:
```js
// astro.config.mjs
export default defineConfig({
@@ -1603,7 +1949,7 @@ export default defineConfig({
locales: ["en", "fr"],
routing: {
prefixDefaultLocale: true,
- redirectToDefaultLocale: false
+ redirectToDefaultLocale: true
}
}
})
diff --git a/src/content/docs/en/reference/content-loader-reference.mdx b/src/content/docs/en/reference/content-loader-reference.mdx
index ac5bbb40a78b4..58502fe96e181 100644
--- a/src/content/docs/en/reference/content-loader-reference.mdx
+++ b/src/content/docs/en/reference/content-loader-reference.mdx
@@ -3,20 +3,26 @@ title: Astro Content Loader API
sidebar:
label: Content Loader API
i18nReady: true
+tableOfContents:
+ minHeadingLevel: 2
+ maxHeadingLevel: 3
---
import Since from '~/components/Since.astro';
+import ReadMore from '~/components/ReadMore.astro';
-Astro's Content Loader API allows you to load your data from any source, local or remote, and interact with Astro's content layer to manage your [content collections](/en/guides/content-collections/).
+Astro's Content Loader API allows you to load your data from any source, local or remote, and interact with Astro's content layer to manage your [content collections](/en/guides/content-collections/).
-## What is a loader?
+This API includes two ready-to-use loaders for content stored locally. It also provides tools for building your own custom objects that can load data from any source into content collections.
-Astro loaders allow you to load data into [content collections](/en/guides/content-collections/), which can then be used in pages and components. The [built-in `glob()` and `file()` loaders](/en/guides/content-collections/#built-in-loaders) are used to load content from the file system, and you can create your own loaders to load content from other sources.
+Learn more about [querying data loaded from build-time loaders](/en/guides/content-collections/#querying-build-time-collections) or [accessing live data from live loaders](/en/guides/content-collections/#accessing-live-data) with guided explanations and example usage in the content collections guide.
-Each collection needs [a loader defined in its schema](/en/guides/content-collections/#defining-the-collection-loader). You can define a loader inline in your project's `src/content.config.ts` file, share one loader between multiple collections, or even [publish your loader to NPM as a package](/en/reference/publish-to-npm/) to share with others and be included in our integrations library.
+## Build-time loaders
-## Built-in loaders
+Build-time loaders are objects with a [`load()` method](#load) that is called at build time to fetch data and update the data store. This object can also define a schema for the entries, which can be used to validate the data and generate static types.
-Astro provides two built-in loaders to help you fetch your collections. Both offer options to suit a wide range of use cases.
+Astro's [`glob()`](#glob-loader) and [`file()`](#file-loader) loaders are examples of object loaders that are provided out-of-the-box for use with local content. For remote content, no prebuilt loaders are provided. You will have to build an object loader or use a [community-published loader](https://astro.build/integrations/?search=&categories%5B%5D=loaders) to retrieve remote content and interact with the data store.
+
+For simple data fetching, you can also [define a loader as an async function](#defining-a-loader-as-a-function) that returns an array or object containing entries.
### `glob()` loader
@@ -30,19 +36,17 @@ The `glob()` loader creates entries from directories of files from anywhere on t
This loader accepts an object with the following properties: `pattern`, `base` (optional), and `generateId` (optional).
-```ts title="src/content.config.ts" {2,6,11,17-21}
+```ts title="src/content.config.ts"
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
const pages = defineCollection({
/* Retrieve all Markdown files in your pages directory. */
loader: glob({ pattern: "**/*.md", base: "./src/data/pages" }),
- schema: /* ... */
});
const blog = defineCollection({
/* Retrieve all Markdown and MDX files in your blog directory. */
loader: glob({ pattern: "**/*.(md|mdx)", base: "./src/data/blog" }),
- schema: /* ... */
});
const authors = defineCollection({
/* Retrieve all JSON files in your authors directory while retaining
@@ -52,8 +56,9 @@ const authors = defineCollection({
base: "./src/data/authors",
generateId: ({ entry }) => entry.replace(/\.json$/, ''),
}),
- schema: /* ... */
});
+
+export const collections = { pages, blog, authors };
```
#### `pattern`
@@ -99,26 +104,28 @@ By default it uses [`github-slugger`](https://github.com/Flet/github-slugger) to
-The `file()` loader creates entries from a single file that contains an array of objects with a unique `id` field, or an object with IDs as keys and entries as values. It supports JSON, YAML, or TOML files and you can provide a custom `parser` for data files it cannot parse by default.
+The `file()` loader creates entries from a single file that contains an array of objects with a unique `id` field, or an object with IDs as keys and entries as values.
+
+It supports JSON, YAML, or TOML files and you can provide a custom `parser` for data files it cannot parse by default.
-This loader accepts a `fileName` property and an optional object as second argument:
+This loader accepts a `fileName` property and an optional options object as second argument:
-```ts title="src/content.config.ts" {2,6,11-13}
+```ts title="src/content.config.ts"
import { defineCollection } from 'astro:content';
import { file } from 'astro/loaders';
const authors = defineCollection({
/* Retrieve all entries from a JSON file. */
loader: file("src/data/authors.json"),
- schema: /* ... */
});
const products = defineCollection({
/* Retrieve all entries from a CSV file using a custom parser. */
loader: file("src/data/products.csv", {
parser: (fileContent) => { /* your parser logic */ },
}),
- schema: /* ... */
});
+
+export const collections = { authors, products };
```
#### `fileName`
@@ -143,22 +150,111 @@ An optional object with the following properties:
-**Type:** `(text: string) => Record> | Array>`
+**Type:** `(text: string) => Record> | Array> | Promise> | Array>>`
-A callback function to create a collection from a file’s contents. Use it when you need to process file not supported by default (e.g. `.csv`) or when using [nested `.json` documents](/en/guides/content-collections/#nested-json-documents).
+A callback function to create a collection from a file’s contents. Use it when you need to process files other than JSON, YAML, or TOML that not supported by default (e.g. `.csv`) or when using [nested `.json` documents](/en/guides/content-collections/#nested-json-documents).
+
+### Building a loader
+
+The Content Loader API is flexible and full-featured, allowing for a variety of data fetching options. It is possible to build both simple and complex loaders. Your custom loader will depend on both the source and the shape of your data, as well as how you choose to manage the persistent data storage layer.
+
+Most loaders will export a function that accepts configuration options and returns a [loader object](#the-loader-object) including a `name` for your loader, a `load()` method, and a `schema` defining your entries.
+
+#### Loading collections into the data store
+
+The [`load()`](#load) function returned in the loader object defines how your content is fetched, parsed, validated and updated. It accepts a `context` object that allows you to customize your data handling in a variety of ways and interact with the data store. A typical `load()` function will:
+
+- Fetch your data from a source.
+- Clear the existing data store.
+- Parse and validate your data entries according to a provided schema.
+- Update the data store with new entries.
+
+The `load()` method also provides helpers to log messages to the console, render content to HTML, watch for changes in dev mode and reload data, provide access to metadata
+and even the full Astro config, and more.
+
+See the full [`LoaderContext`](#loadercontext) list of properties for all options available to the `load()` function.
+
+#### Providing a schema
+
+Providing a Zod [`schema`](#schema) in your loader allows you to validate your fetched content entries with [`parseData()`](#parsedata) before adding them to the data [store](#store). This schema will also be used as the collection's default schema when one does not exist in `src/content.config.ts` to provide type safety and editor tooling. You do not also need a schema defined in the content collection if the loader provides this property.
+
+However, if the content collection also [defines a schema](/en/guides/content-collections/#defining-the-collection-schema), that schema will be used instead of your loader's schema. This is to allow users of your loader to extend its schema, or transform data for use in their project. If you are [publishing and distributing a loader](#distributing-your-loader) for others to use, you may wish to document this behavior and encourage users not to define a collection schema themselves, or how to do so safely if they need data returned in a different format.
+
+If you need to dynamically generate the schema based on the configuration options or by introspecting an API, you can use [`createSchema()`](#createschema) instead.
+
+#### Loader example
+
+The following example shows a loader that fetches data from a provided feed URL (using a custom `loadFeedData` utility) and updates the data store with new entries each time the site is built:
+
+```ts title="src/feed-loader.ts"
+// 1. Import the `Loader` type and any other dependencies needed
+import type { Loader } from 'astro/loaders';
+import { z } from 'astro/zod';
+import { loadFeedData } from "./feed.js";
+
+// 2. Define any options that your loader needs
+export function myLoader(options: { url: string, apiKey: string }) {
+ const feedUrl = new URL(options.url);
+ // 3. Return a loader object
+ return {
+ name: "feed-loader",
+ load: async ({ store, parseData }) => {
+ const feed = await loadFeedData(feedUrl, options.apiKey);
+
+ store.clear();
+
+ for (const item of feed.items) {
+ const id = item.guid;
+ const data = await parseData({
+ id,
+ data: item,
+ });
+ store.set({
+ id,
+ data,
+ });
+ }
+ },
+ // 4. Define the schema of an entry.
+ schema: z.object({
+ // ...
+ })
+ } satisfies Loader;
+}
+```
+
+#### Defining your collection with your loader
+
+Use your custom loader as the value of the `loader` property when you define your collection in `src/content.config.ts`. Configuration options can be passed to your loader as arguments:
+
+```ts title="src/content.config.ts"
+import { defineCollection } from 'astro:content';
+import { feedLoader } from './feed-loader.ts';
+
+const blog = defineCollection({
+ loader: feedLoader({
+ url: "https://api.example.com/posts",
+ apiKey: "my-secret",
+ }),
+});
+
+export const collections = { blog };
+```
-## Loader types
+### Defining a loader as a function
-Loaders can be defined either as a simple function that returns an array of entries or with the more powerful object Content Loader API for more control over the loading process.
+For simple data fetches that do not need custom data store handling, validation, logging, or any other helpers provided by the [build-time loader object](#the-loader-object), you can define your loader as a function.
-### Inline loaders
+The function can be async and must return either an array of entries that each contain a unique `id` field, or an object where each key is a unique ID and each value is the entry.
-An inline loader is an async function that returns an array or object containing entries. Use this for simple loaders, particularly those that are defined inline in the `src/content.config.ts` file.
+This pattern provides a convenient shorthand to accomplish the basic tasks normally performed by the `load()` function to [load collections into the data store](#loading-collections-into-the-data-store). At build-time, the loader will automatically clear the data store and reload all the entries. No further customization options or helpers for data handling are provided.
-The function can be async and must return either an array of entries that each contain a unique `id` field, or an object where each key is a unique ID and each value is the entry. Whenever the loader is invoked, it will clear the store and reload all the entries.
+These loaders are often simple enough that you may choose to define them inline in the `src/content.config.ts` file:
```ts title="src/content.config.ts"
+import { defineCollection } from "astro:content";
+
const countries = defineCollection({
loader: async () => {
const response = await fetch("https://restcountries.com/v3.1/all");
@@ -170,105 +266,479 @@ const countries = defineCollection({
...country,
}));
},
- schema: /* ... */
});
+
+export const collections = { countries };
```
-### Object loaders
+## Live Loaders
-A loader is an object with a `load()` method that is called at build time to fetch data and update the data store. It allows entries to be updated incrementally, or for the store to be cleared only when necessary. It can also define a schema for the entries, which can be used to validate the data and generate static types.
+The Live Loader API is built to handle querying any data in real time. Live loaders can filter incoming data and verify content with type safety. Since live loaders fetch data fresh upon every request, there is no data store to update. These loaders are designed to return either data or an `Error` object to allow you to handle errors gracefully.
-The recommended pattern is to define a function that accepts configuration options and returns the loader object, in the same way that you would normally define an Astro integration or Vite plugin.
+### Building a live loader
+Most live loaders will export a function that accepts configuration options and returns a [live loader object](#the-liveloader-object) including a `name` for your loader and two methods to define how to load your collection of entries and how to load a single entry: `loadCollection()` and `loadEntry()`.
-```ts title=loader.ts
-import type { Loader, LoaderContext } from 'astro/loaders';
-import { z } from 'astro/zod';
-import { loadFeedData } from "./feed.js";
+#### Loading live data
-// Define any options that the loader needs
-export function myLoader(options: { url: string, apiKey: string }): Loader {
- // Configure the loader
- const feedUrl = new URL(options.url);
- // Return a loader object
+To return data about your collection, you must provide a [`loadCollection()`](#loadcollection) function that fetches data, and returns an array of content [`entries`](#entries-1) or an error.
+
+To return a single live collection entry, you must provide a [`loadEntry()`](#loadentry) function that fetches data filtered for a given `id`, and returns a single [`entry`](#livedataentry), `undefined`, or an error.
+
+The data fetching for both of these functions is typically done using a [`try...catch` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) to [handle errors when accessing live data](#error-handling-in-live-loaders).
+
+See the full [Live Loader API](#live-loader-api) for more about the functions and types available for building your live loader.
+
+#### Providing a schema for live loaders
+
+Live loaders do not include a schema property. Instead, you can provide type safety by [defining a Zod schema for your collection](/en/guides/content-collections/#using-zod-schemas-with-live-collections) in `src/live.config.ts`, or by passing generic types to the `LiveLoader` interface for the data they return.
+
+#### Example live loader
+
+The following example shows a live loader that defines data fetching from a CMS (using a custom `fetchFromCMS` utility) for both a collection of entries and a single entry, including type safety and error handling:
+
+```ts title="src/article-loader.ts"
+import type { LiveLoader } from 'astro/loaders';
+import { fetchFromCMS } from './cms-client.js';
+
+interface Article {
+ id: string;
+ title: string;
+ htmlContent: string;
+ author: string;
+}
+
+interface EntryFilter {
+ id: string;
+}
+
+interface CollectionFilter {
+ author?: string;
+}
+
+export function articleLoader(config: { apiKey: string }): LiveLoader {
return {
- name: "my-loader",
- // Called when updating the collection.
- load: async (context: LoaderContext): Promise => {
- // Load data and update the store
- const response = await loadFeedData(feedUrl, options.apiKey);
+ name: 'article-loader',
+ loadCollection: async ({ filter }) => {
+ try {
+ const articles = await fetchFromCMS({
+ apiKey: config.apiKey,
+ type: 'article',
+ filter,
+ });
+
+ return {
+ entries: articles.map((article) => ({
+ id: article.id,
+ data: article,
+ })),
+ };
+ } catch (error) {
+ return {
+ error: new Error('Failed to load articles', { cause: error }),
+ };
+ }
+ },
+ loadEntry: async ({ filter }) => {
+ try {
+ // filter will be { id: "some-id" } when called with a string
+ const article = await fetchFromCMS({
+ apiKey: config.apiKey,
+ type: 'article',
+ id: filter.id,
+ });
+
+ if (!article) {
+ return {
+ error: new Error('Article not found'),
+ };
+ }
+
+ return {
+ id: article.id,
+ data: article,
+ rendered: {
+ html: article.htmlContent,
+ },
+ };
+ } catch (error) {
+ return {
+ error: new Error('Failed to load article', { cause: error }),
+ };
+ }
},
- // Optionally, define the schema of an entry.
- // It will be overridden by user-defined schema.
- schema: async () => z.object({
- // ...
- })
};
}
```
-These configuration options can then be set when defining a collection:
+#### Defining your live collection with your loader
-```ts title="src/content.config.ts" {3,6-9}
-import { defineCollection } from 'astro:content';
-import { z } from 'astro/zod';
-import myLoader from '../../loader.ts';
+Use your custom live loader as the value of the `loader` property when you define your collection in `src/live.config.ts`. Configuration options can be passed to your loader as arguments:
-const blog = defineCollection({
- loader: myLoader({
- url: "https://api.example.com/posts",
+```ts title="src/live.config.ts" {2,5-7}
+import { defineLiveCollection } from 'astro:content';
+import { articleLoader } from './article-loader.ts';
+
+const blog = defineLiveCollection({
+ loader: articleLoader({
apiKey: "my-secret",
- }),
- schema: /* ... */
-});
+ }),
+});
+
+export const collections = { blog };
+```
+
+#### Error handling in live loaders
+
+Live loaders return an [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) subclass for errors. You can create [custom error types](#creating-live-loader-error-types) and use them for more specific error handling if needed. If an error is thrown in the live loader, it will be caught and returned, wrapped in a `LiveCollectionError`.
+
+Astro will generate some errors itself, depending on the response from the live loader:
+
+- If `loadEntry` returns `undefined`, Astro will return a `LiveEntryNotFoundError` to the user.
+- If a schema is defined for the collection and the data does not match the schema, Astro will return a `LiveCollectionValidationError`.
+- If the loader returns an invalid cache hint, Astro will return a `LiveCollectionCacheHintError`. The `cacheHint` field is optional, so if you do not have valid data to return, you can simply omit it.
+
+```ts title="my-loader.ts" {10-12}
+import type { LiveLoader } from 'astro/loaders';
+import type { MyData } from "./types";
+import { MyLoaderError } from './errors';
+
+export function myLoader(config): LiveLoader {
+ return {
+ name: 'my-loader',
+ loadCollection: async () => {
+ // Return your custom error type
+ return {
+ error: new MyLoaderError('Failed to load', 'LOAD_ERROR'),
+ };
+ },
+ // ...
+ };
+}
+```
+
+##### Creating live loader error types
+
+You can create custom error types for [errors returned by your loader](#error-handling-in-live-loaders) and pass them as a generic to get proper typing:
+
+```ts title="my-loader.ts"
+import type { LiveLoader } from "astro/loaders";
+import type { MyData } from "./types"
+
+export class MyLoaderError extends Error {
+ constructor(message: string, public code?: string) {
+ super(message);
+ this.name = 'MyLoaderError';
+ }
+}
+
+export function myLoader(config): LiveLoader {
+ return {
+ name: 'my-loader',
+ loadCollection: async () => {
+ // Return your custom error type
+ return {
+ error: new MyLoaderError('Failed to load', 'LOAD_ERROR'),
+ };
+ },
+ // ...
+ };
+}
+```
+
+When you use `getLiveCollection()` or `getLiveEntry()`, TypeScript will infer the custom error type, allowing you to handle it appropriately:
+
+```astro
+---
+export const prerender = false; // Not needed in 'server' mode
+
+import { getLiveEntry } from 'astro:content';
+import { MyLoaderError } from "../my-loader";
+
+const { entry, error } = await getLiveEntry('products', '123');
+
+if (error) {
+ if (error instanceof MyLoaderError) {
+ console.error(`Loader error: ${error.message} (code: ${error.code})`);
+ } else {
+ console.error(`Unexpected error: ${error.message}`);
+ }
+ return Astro.rewrite('/500');
+}
+---
+```
+
+#### Defining custom filter types
+
+Live loaders can define custom filter types for both `getLiveCollection()` and `getLiveEntry()`. This enables type-safe querying that matches your API's capabilities, making it easier for users to discover available filters and ensure they are used correctly. If you include JSDoc comments in your filter types, the user will see these in their IDE as hints when using the loader.
+
+```ts title="store-loader.ts" "EntryFilter, CollectionFilter" {6,8}
+import type { LiveLoader } from 'astro/loaders';
+import { fetchProduct, fetchCategory, type Product } from './store-client';
+
+interface CollectionFilter {
+ category?: string;
+ /** Minimum price to filter products */
+ minPrice?: number;
+ /** Maximum price to filter products */
+ maxPrice?: number;
+}
+
+interface EntryFilter {
+ /** Alias for `sku` */
+ id?: string;
+ slug?: string;
+ sku?: string;
+}
+
+export function productLoader(config: {
+ apiKey: string;
+ endpoint: string;
+}): LiveLoader {
+ return {
+ name: 'product-loader',
+ loadCollection: async ({ filter }) => {
+ // filter is typed as CollectionFilter
+ const data = await fetchCategory({
+ apiKey: config.apiKey,
+ category: filter?.category ?? 'all',
+ minPrice: filter?.minPrice,
+ maxPrice: filter?.maxPrice,
+ });
+
+ return {
+ entries: data.products.map((product) => ({
+ id: product.sku,
+ data: product,
+ })),
+ };
+ },
+ loadEntry: async ({ filter }) => {
+ // filter is typed as EntryFilter | { id: string }
+ const product = await fetchProduct({
+ apiKey: config.apiKey,
+ slug: filter.slug,
+ sku: filter.sku || filter.id,
+ });
+ if (!product) {
+ return {
+ error: new Error('Product not found'),
+ };
+ }
+ return {
+ id: product.sku,
+ data: product,
+ };
+ },
+ };
+}
+```
+
+#### Cache hints
+
+Live loaders can provide cache hints to help with response caching. You can use this data to send HTTP cache headers or otherwise inform your caching strategy.
+
+```ts title="my-loader.ts"
+import type { LiveLoader } from "astro/loaders";
+import { loadStoreProduct, loadStoreProducts, getLastModifiedDate } from "./store";
+import type { Product, ProductEntryFilter, ProductCollectionFilter } from "./types";
+
+export function myLoader(config): LiveLoader {
+ return {
+ name: 'cached-loader',
+ loadCollection: async ({ filter }) => {
+ const products = await loadStoreProducts(filter);
+ return {
+ entries: products.map((item) => ({
+ id: item.id,
+ data: item,
+ // You can optionally provide cache hints for each entry
+ cacheHint: {
+ tags: [`product-${item.id}`, `category-${item.category}`],
+ },
+ })),
+ cacheHint: {
+ // All fields are optional, and are combined with each entry's cache hints
+ // tags are merged from all entries
+ // lastModified is the most recent lastModified of all entries and the collection
+ lastModified: getLastModifiedDate(products),
+ tags: ['products'],
+ },
+ };
+ },
+ loadEntry: async ({ filter }) => {
+ const item = await loadStoreProduct(filter);
+ return {
+ id: item.id,
+ data: item,
+ cacheHint: {
+ lastModified: new Date(item.lastModified),
+ tags: [`product-${item.id}`, `category-${item.category}`],
+ },
+ };
+ },
+ };
+}
+```
+
+You can then use these hints in your pages:
+
+```astro title="src/pages/store/[id].astro"
+---
+export const prerender = false; // Not needed in 'server' mode
+
+import { getLiveEntry } from 'astro:content';
+
+const { entry, error, cacheHint } = await getLiveEntry('products', Astro.params.id);
+
+if (error) {
+ return Astro.redirect('/404');
+}
+
+// Apply cache hints to response headers
+if (cacheHint?.tags) {
+ Astro.response.headers.set('Cache-Tag', cacheHint.tags.join(','));
+}
+
+if (cacheHint?.lastModified) {
+ Astro.response.headers.set('Last-Modified', cacheHint.lastModified.toUTCString());
+}
+---
+
+{entry.data.name}
+{entry.data.description}
```
+:::note
+Cache hints only provide values that can be used in other parts of your project and do not automatically cause the response to be cached by Astro. You can use them to create your own caching strategy, such as setting HTTP headers or using a CDN.
+:::
+
+## Distributing your loader
+
+Loaders can be defined in your site or as a separate npm package. If you want to share your loader with the community, you can [publish it to npm with the `withastro` and `astro-loader` keywords](/en/reference/publish-to-npm/#packagejson-data).
+
+A loader should export a function that returns a `LiveLoader` object for live loaders or a `Loader` object for build-time loaders, allowing users to configure it with their own settings.
+
## Object loader API
-The API for [inline loaders](#inline-loaders) is very simple, and is shown above. This section shows the API for defining an object loader.
+
+
+This section shows the API for defining a [build-time object loader](#building-a-loader).
### The `Loader` object
-The loader object has the following properties:
+
+
+
+**Type:** `Loader`
+
+
+A loader function returns an object with [two required properties](#loader-properties). In addition to providing a name for the loader, this object describes how to fetch the collection data.
+
+Optionally, you can return a third property defining a schema to validate your collection entries. Use the [Typescript `satisfies` operator](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator) instead of a return type annotation to provide type safety inside your loader object and to preserve type inference when your loader is used in a collection.
+
+#### Loader properties
#### `name`
**Type**: `string`
+
A unique name for the loader, used in logs and [for conditional loading](/en/reference/integrations-reference/#refreshcontent-option).
-#### `load`
+#### `load()`
**Type**: (context: LoaderContext ) => Promise<void>
+
-An async function that is called at build time to load data and update the store. See [`LoaderContext`](#loadercontext) for more information.
+An async function that is called at build time to load data and update the store. It is passed a [`LoaderContext`](#loadercontext) object that contains helper functions and properties for writing your loader's implementation logic, as well as the `store` database and methods for interacting with it.
#### `schema`
-**Type**: `ZodSchema | Promise | (() => ZodSchema | Promise)`
+**Type**: `ZodSchema`
+
An optional [Zod schema](/en/guides/content-collections/#defining-datatypes-with-zod) that defines the shape of the entries. It is used to both validate the data and also to generate TypeScript types for the collection.
-If a function is provided, it will be called at build time before `load()` to generate the schema. You can use this to dynamically generate the schema based on the configuration options or by introspecting an API.
+When you need to dynamically generate the schema at build time based on configuration options or by introspecting an API, use [`createSchema()`](#createschema) instead.
+
+If present, it will be overridden by any Zod `schema` defined for the collection in the `src/content.config.ts` file.
+
+#### `createSchema()`
+
+
+
+**Type**: `() => Promise<{ schema: ZodSchema; types: string }>`
+
+
+
+An optional async function that returns an object containing a [Zod schema](/en/guides/content-collections/#defining-datatypes-with-zod) and types. It is used to dynamically generate the schema at build time based on the configuration options or by introspecting an API.
+
+When you only need to provide a static schema, provide a Zod validation object using [`schema`](#schema) instead.
+
+If present, it will be overridden by any Zod `schema` defined for the collection in the `src/content.config.ts` file.
+
+The returned `types` contents will be written to a TypeScript file, and must export an `Entry` type or interface:
+
+```ts title="src/feed-loader.ts" ins={27-35}
+import type { Loader } from 'astro/loaders';
+import { z } from 'astro/zod';
+import { loadFeedData, getSchema, getTypes } from "./feed.js";
+
+export function myLoader(options: { url: string, apiKey: string }) {
+ const feedUrl = new URL(options.url);
+
+ return {
+ name: "feed-loader",
+ load: async ({ store, parseData }) => {
+ const feed = await loadFeedData(feedUrl, options.apiKey);
+
+ store.clear();
+
+ for (const item of feed.items) {
+ const id = item.guid;
+ const data = await parseData({
+ id,
+ data: item,
+ });
+ store.set({
+ id,
+ data,
+ });
+ }
+ },
+ createSchema: async () => {
+ const schema = await getSchema();
+ const types = await getTypes();
+
+ return {
+ schema,
+ types: `export type Entry = ${types}`,
+ };
+ },
+ } satisfies Loader;
+}
+```
### `LoaderContext`
-This object is passed to the `load()` method of the loader, and contains the following properties:
+This object is passed to the [`load()`](#load) method of the loader, and contains the following properties:
#### `collection`
**Type**: `string`
+
The unique name of the collection. This is the key in the `collections` object in the `src/content.config.ts` file.
@@ -278,6 +748,7 @@ The unique name of the collection. This is the key in the `collections` object i
**Type**: [`DataStore`](#datastore)
+
A database to store the actual data. Use this to update the store with new entries. See [`DataStore`](#datastore) for more information.
@@ -287,6 +758,7 @@ A database to store the actual data. Use this to update the store with new entri
**Type**: `MetaStore`
+
A key-value store scoped to the collection, designed for things like sync tokens and last-modified times. This metadata is persisted between builds alongside the collection data but is only available inside the loader.
@@ -302,33 +774,72 @@ meta.set("lastModified", new Date().toISOString());
**Type**: [`AstroIntegrationLogger`](/en/reference/integrations-reference/#astrointegrationlogger)
+
-A logger that can be used to log messages to the console. Use this instead of `console.log` for more helpful logs that include the loader name in the log message. See [`AstroIntegrationLogger`](/en/reference/integrations-reference/#astrointegrationlogger) for more information.
+A logger that can be used to log messages to the console. Use this instead of `console.log` for more helpful logs that include loader-specific content such as the loader name or information about the loading process in the log message. See [`AstroIntegrationLogger`](/en/reference/integrations-reference/#astrointegrationlogger) for more information.
+
+```ts title="Extract from the file() loader" {10} "logger"
+return {
+ name: 'file-loader',
+ load: async ({ config, store, logger, watcher }) => {
+ const url = new URL(fileName, config.root);
+ const filePath = fileURLToPath(url);
+ await syncData(filePath, store);
+
+ watcher?.on('change', async (changedPath) => {
+ if (changedPath === filePath) {
+ logger.info(`Reloading data from ${fileName}`);
+ await syncData(filePath, store);
+ }
+ });
+ },
+};
+```
#### `config`
**Type**: `AstroConfig`
+
The full, resolved Astro configuration object with all defaults applied. See [the configuration reference](/en/reference/configuration-reference/) for more information.
-#### `parseData`
+```ts title="Extract from the file() loader" {4} "config"
+return {
+ name: 'file-loader',
+ load: async ({ config, store, logger, watcher }) => {
+ const url = new URL(fileName, config.root);
+ const filePath = fileURLToPath(url);
+ await syncData(filePath, store);
+
+ watcher?.on('change', async (changedPath) => {
+ if (changedPath === filePath) {
+ logger.info(`Reloading data from ${fileName}`);
+ await syncData(filePath, store);
+ }
+ });
+ },
+};
+```
+
+#### `parseData()`
**Type**: `(props: ParseDataOptions) => Promise`
+
Validates and parses the data according to the collection schema. Pass data to this function to validate and parse it before storing it in the data store.
-```ts title=loader.ts {14-17}
+```ts title=loader.ts {15-18}
import type { Loader } from "astro/loaders";
import { loadFeed } from "./feed.js";
-export function feedLoader({ url }): Loader {
+export function feedLoader({ url }) {
const feedUrl = new URL(url);
return {
name: "feed-loader",
@@ -338,8 +849,9 @@ export function feedLoader({ url }): Loader {
store.clear();
for (const item of feed.items) {
+ const id = item.guid;
const data = await parseData({
- id: item.guid,
+ id,
data: item,
});
store.set({
@@ -348,11 +860,11 @@ export function feedLoader({ url }): Loader {
});
}
},
- };
+ } satisfies Loader;
}
```
-#### `renderMarkdown`
+#### `renderMarkdown()`
@@ -362,7 +874,7 @@ export function feedLoader({ url }): Loader {
Renders a Markdown string to HTML, returning a `RenderedContent` object.
-This allows you to render Markdown content directly within your loaders using the same Markdown processing as Astro's built-in `glob` loader and provides access to the `render()` function and ` ` component for [rendering body content](/en/guides/content-collections/#rendering-body-content).
+This allows you to render Markdown content directly within your loaders using the same Markdown processing as Astro's built-in `glob()` loader and provides access to the `render()` function and ` ` component for [rendering body content](/en/guides/content-collections/#rendering-body-content).
Assign this object to the [rendered](#rendered) field of the [DataEntry](#dataentry) object to allow users to [render the content in a page](/en/guides/content-collections/#rendering-body-content).
@@ -370,7 +882,7 @@ Assign this object to the [rendered](#rendered) field of the [DataEntry](#dataen
import type { Loader } from 'astro/loaders';
import { loadFromCMS } from './cms.js';
-export function myLoader(settings): Loader {
+export function myLoader(settings) {
return {
name: 'cms-loader',
async load({ renderMarkdown, store }) {
@@ -387,24 +899,25 @@ export function myLoader(settings): Loader {
});
}
},
- };
+ } satisfies Loader;
}
```
-#### `generateDigest`
+#### `generateDigest()`
**Type**: `(data: Record | string) => string`
+
Generates a non-cryptographic content digest of an object or string. This can be used to track if the data has changed by setting [the `digest` field](#digest) of an entry.
-```ts title=loader.ts {19,24}
+```ts title=loader.ts {20,25}
import type { Loader } from "astro/loaders";
import { loadFeed } from "./feed.js";
-export function feedLoader({ url }): Loader {
+export function feedLoader({ url }) {
const feedUrl = new URL(url);
return {
name: "feed-loader",
@@ -414,8 +927,9 @@ export function feedLoader({ url }): Loader {
store.clear();
for (const item of feed.items) {
+ const id = item.guid;
const data = await parseData({
- id: item.guid,
+ id,
data: item,
});
@@ -428,7 +942,7 @@ export function feedLoader({ url }): Loader {
});
}
},
- };
+ } satisfies Loader;
}
```
@@ -437,6 +951,7 @@ export function feedLoader({ url }): Loader {
**Type**: `FSWatcher`
+
When running in dev mode, this is a filesystem watcher that can be used to trigger updates. See [`ViteDevServer`](https://vite.dev/guide/api-javascript.html#vitedevserver) for more information.
@@ -464,12 +979,16 @@ return {
**Type**: `Record`
+
If the loader has been triggered by an integration, this may optionally contain extra data set by that integration. It is only set when the loader is triggered by an integration. See the [`astro:server:setup`](/en/reference/integrations-reference/#refreshcontent-option) hook reference for more information.
-```ts title=loader.ts {5-8}
-export function myLoader(options: { url: string }): Loader {
+```ts title=loader.ts {8-11}
+import type { Loader } from "astro/loaders";
+import { processWebhook } from "./lib/webhooks";
+
+export function myLoader(options: { url: string }) {
return {
name: "my-loader",
load: async ({ refreshContextData, store, logger }) => {
@@ -479,7 +998,7 @@ export function myLoader(options: { url: string }): Loader {
}
// ...
},
- };
+ } satisfies Loader;
}
```
@@ -487,11 +1006,12 @@ export function myLoader(options: { url: string }): Loader {
The data store is a loader's interface to the content collection data. It is a key-value (KV) store, scoped to the collection, and therefore a loader can only access the data for its own collection.
-#### `get`
+#### `get()`
**Type**: (key: string) => DataEntry | undefined
+
Get an entry from the store by its ID. Returns `undefined` if the entry does not exist.
@@ -502,19 +1022,21 @@ const existingEntry = store.get("my-entry");
The returned object is a [`DataEntry`](#dataentry) object.
-#### `set`
+#### `set()`
**Type**: (entry: DataEntry ) => boolean
+
Used after data has been [validated and parsed](#parsedata) to add an entry to the store, returning `true` if the entry was set. This returns `false` when the [`digest`](#digest) property determines that an entry has not changed and should not be updated.
-```ts title=loader.ts {7-14}
+```ts title=loader.ts {8-15}
for (const item of feed.items) {
+ const id = item.guid;
const data = await parseData({
- id: item.guid,
+ id,
data: item,
});
const digest = generateDigest(data);
@@ -529,56 +1051,62 @@ Used after data has been [validated and parsed](#parsedata) to add an entry to t
}
```
-#### `entries`
+#### `entries()`
-**Type**: `() => Array<[id: string, DataEntry]>`
+**Type**: () => Array\<[id: string, DataEntry ]\>
+
Get all entries in the collection as an array of key-value pairs.
-#### `keys`
+#### `keys()`
**Type**: `() => Array`
+
Get all the keys of the entries in the collection.
-#### `values`
+#### `values()`
-**Type**: `() => Array`
+**Type**: () => Array\<DataEntry \>
+
Get all entries in the collection as an array.
-#### `delete`
+#### `delete()`
**Type**: `(key: string) => void`
+
Delete an entry from the store by its ID.
-#### `clear`
+#### `clear()`
**Type**: `() => void`
+
Clear all entries from the collection.
-#### `has`
+#### `has()`
**Type**: `(key: string) => boolean`
+
Check if an entry exists in the store by its ID.
@@ -592,26 +1120,29 @@ This is the type of the object that is stored in the data store. It has the foll
**Type**: `string`
+
-An identifier for the entry, which must be unique within the collection. This is used to look up the entry in the store and is the key used with `getEntry` for that collection.
+An identifier for the entry, which must be unique within the collection. This is used to look up the entry in the store and is the key used with [`getEntry()`](/en/reference/modules/astro-content/#getentry) for that collection.
#### `data`
**Type**: `Record`
+
The actual data for the entry. When a user accesses the collection, this will have TypeScript types generated according to the collection schema.
-It is the loader's responsibility to use [`parseData`](#parsedata) to validate and parse the data before storing it in the data store: no validation is done when getting or setting the data.
+It is the loader's responsibility to use [`parseData()`](#parsedata) to validate and parse the data before storing it in the data store: no validation is done when getting or setting the data.
#### `filePath`
**Type**: `string | undefined`
+
A path to the file that is the source of this entry, relative to the root of the site. This only applies to file-based loaders and is used to resolve paths such as images or other assets.
@@ -623,6 +1154,7 @@ If not set, then any fields in the schema that use [the `image()` helper](/en/gu
**Type**: `string | undefined`
+
The raw body of the entry, if applicable. If the entry includes [rendered content](#rendered), then this field can be used to store the raw source. This is optional and is not used internally.
@@ -632,6 +1164,7 @@ The raw body of the entry, if applicable. If the entry includes [rendered conten
**Type**: `string | undefined`
+
An optional content digest for the entry. This can be used to check if the data has changed.
@@ -645,6 +1178,7 @@ The format of the digest is up to the loader, but it must be a string that chang
**Type**: `RenderedContent | undefined`
+
Stores an object with an entry's rendered content and metadata if it has been rendered to HTML. For example, this can be used to store the rendered content of a Markdown entry, or HTML from a CMS.
@@ -671,3 +1205,234 @@ The format of the `RenderedContent` object is:
```
If the entry has Markdown content then you can use the [`renderMarkdown()`](#rendermarkdown) function to generate this object from the Markdown string.
+
+## Live loader API
+
+
+
+This section shows the API for defining a [live loader](#live-loaders).
+
+### The `LiveLoader` object
+
+
+
+**Type:** `LiveLoader`
+
+
+
+A live loader function returns an object with [three required live loader properties](#live-loader-properties). In addition to providing a name for the loader, this object describes how to fetch both single entries and an entire collection from your live data source.
+
+Use the `LiveLoader` generic type to provide type safety in your loader. This type accepts the following type parameters, in this order:
+
+- **`TData`** (defaults to `Record`): The data structure of each entry returned by the loader.
+- **`TEntryFilter`** (defaults to `never`): The filter object type accepted by [`getLiveEntry()`](/en/reference/modules/astro-content/#getliveentry) and accessible in [`loadEntry()`](#loadentry). Use `never` when you don't support filtering single entries.
+- **`TCollectionFilter`** (defaults to `never`): The filter object type accepted by [`getLiveCollection()`](/en/reference/modules/astro-content/#getlivecollection) and accessible in [`loadCollection()`](#loadcollection). Use `never` when you don't support filtering collections.
+- **`TError`** (defaults to `Error`): A [custom `Error` class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#custom_error_types) that can be returned by the loader for more granular error handling.
+
+#### Live loader properties
+
+##### `name`
+
+
+
+**Type:** `string`
+
+
+
+
+A unique name for the loader, used in logs.
+
+##### `loadCollection()`
+
+
+
+**Type:** (context: LoadCollectionContext \) => Promise\<LiveDataCollection \ | \{ error: TError; \}\>
+
+
+
+Defines a method to load a collection of entries. This function receives a [context object](#loadcollectioncontext) containing an optional `filter` property and must return the data associated with this collection or the errors.
+
+##### `loadEntry()`
+
+
+
+**Type:** (context: LoadEntryContext \) => Promise\<LiveDataEntry \ | undefined | \{ error: TError; \}\>
+
+
+
+Defines a method to load a single entry. This function receives a [context object](#loadentrycontext) containing a `filter` property and returns either the data associated with the requested entry, `undefined` when the entry cannot be found, or the errors.
+
+### `LoadCollectionContext`
+
+
+
+**Type:** `{ filter?: TCollectionFilter; }`
+
+
+
+This object is passed to the [`loadCollection()` method](#loadcollection) of the loader and contains the following properties:
+
+#### `filter`
+
+
+
+**Type:** `Record | never`
+**Default:** `never`
+
+
+
+An object describing the [filters supported by your loader](#defining-custom-filter-types).
+
+### `LoadEntryContext`
+
+
+
+**Type:** `{ filter: TEntryFilter; }`
+
+
+
+This object is passed to the [`loadEntry()` method](#loadentry) of the loader and contains the following properties:
+
+#### `filter`
+
+
+
+**Type:** `Record | never`
+**Default:** `never`
+
+
+
+An object describing the [filters supported by your loader](#defining-custom-filter-types).
+
+
+### `LiveDataEntry`
+
+
+
+**Type:** \{ id: string; data: TData; rendered?: \{ html: string \}; cacheHint?: CacheHint ; \}
+
+
+
+This is the type object that is returned by the [`loadEntry()`](#loadentry) method. It contains the following properties:
+
+#### `id`
+
+
+
+**Type**: `string`
+
+
+
+An identifier for the entry, which must be unique within the collection. This is the key used with [`getLiveEntry()`](/en/reference/modules/astro-content/#getliveentry) for that collection.
+
+#### `data`
+
+
+
+**Type**: `Record`
+
+
+
+The actual data for the entry. When a user accesses the collection, this will have TypeScript types generated according to the collection schema.
+
+It is the loader's responsibility to validate and parse the data before returning it.
+
+#### `rendered`
+
+
+
+**Type**: `{ html: string }`
+
+
+
+An object with an entry's rendered content if it has been rendered to HTML. For example, this can be the rendered content of a Markdown entry, or HTML from a CMS.
+
+If this field is provided, then [the `render()` function and ` ` component](/en/guides/content-collections/#rendering-body-content) are available to render the entry in a page.
+
+If the loader does not return a `rendered` property for an entry, the ` ` component will render nothing.
+
+#### `cacheHint`
+
+
+
+**Type:** [`CacheHint`](#cachehint-2)
+
+
+
+An optional object to provide a hint for how to cache this specific entry.
+
+### `LiveDataCollection`
+
+
+
+**Type:** \{ entries: Array\<LiveDataEntry \\>; cacheHint?: CacheHint ; \}
+
+
+
+This is the type object that is returned by the [`loadCollection()`](#loadcollection) method. It contains the following properties:
+
+#### `entries`
+
+
+
+**Type:** Array\<LiveDataEntry \\>
+
+
+
+An array of [`LiveDataEntry`](#livedataentry) objects.
+
+#### `cacheHint`
+
+
+
+**Type:** [`CacheHint`](#cachehint-2)
+
+
+
+An optional object providing guidance on how to cache this collection. This object will be merged with the cache hints defined for each individual entry, if provided.
+
+### `CacheHint`
+
+An object that loaders can return through the `cacheHint` property in [`LiveDataCollection`](#livedatacollection) or [`LiveDataEntry`](#livedataentry) to provide hints to assist in caching the response. This contains the following properties:
+
+#### `tags`
+
+
+
+**Type:** `Array`
+
+
+
+An array of string identifiers allowing fine-grained cache control. This allows you to group related content and selectively invalidate cached responses when specific content changes.
+
+The following example defines cache hint tags for a collection of posts filtered by author:
+
+```ts
+return {
+ /* ... */
+ cacheHint: {
+ tags: ["posts", `posts-${filter.author}`],
+ },
+};
+```
+
+#### `lastModified`
+
+
+
+**Type:** `Date`
+
+
+
+The date of the last modification of the content (e.g., the last update of an entry in a collection). This can be used to set HTTP cache headers like [`Last-Modified`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Last-Modified) and [`If-Modified-Since`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/If-Modified-Since).
+
+The following example defines a cache hint for a single product using its last update date:
+
+```ts
+return {
+ /* ... */
+ cacheHint: {
+ lastModified: new Date(product.updatedAt)
+ },
+};
+```
diff --git a/src/content/docs/en/reference/error-reference.mdx b/src/content/docs/en/reference/error-reference.mdx
index 6736cecfd454e..967a3f06e6054 100644
--- a/src/content/docs/en/reference/error-reference.mdx
+++ b/src/content/docs/en/reference/error-reference.mdx
@@ -31,7 +31,7 @@ The following reference is a complete list of the errors you may encounter while
- [**InvalidGetStaticPathsEntry**](/en/reference/errors/invalid-get-static-paths-entry/) Invalid entry inside getStaticPath's return value
- [**InvalidGetStaticPathsReturn**](/en/reference/errors/invalid-get-static-paths-return/) Invalid value returned by getStaticPaths.
- [**GetStaticPathsExpectedParams**](/en/reference/errors/get-static-paths-expected-params/) Missing params property on `getStaticPaths` route.
-- [**GetStaticPathsInvalidRouteParam**](/en/reference/errors/get-static-paths-invalid-route-param/) Invalid value for `getStaticPaths` route parameter.
+- [**GetStaticPathsInvalidRouteParam**](/en/reference/errors/get-static-paths-invalid-route-param/) Invalid route parameter returned by `getStaticPaths()`.
- [**GetStaticPathsRequired**](/en/reference/errors/get-static-paths-required/) `getStaticPaths()` function required for dynamic routes.
- [**ReservedSlotName**](/en/reference/errors/reserved-slot-name/) Invalid slot name.
- [**NoAdapterInstalled**](/en/reference/errors/no-adapter-installed/) Cannot use Server-side Rendering without an adapter.
@@ -80,6 +80,7 @@ The following reference is a complete list of the errors you may encounter while
- [**IncorrectStrategyForI18n**](/en/reference/errors/incorrect-strategy-for-i18n/) You can't use the current function with the current strategy
- [**NoPrerenderedRoutesWithDomains**](/en/reference/errors/no-prerendered-routes-with-domains/) Prerendered routes aren't supported when internationalization domains are enabled.
- [**MissingMiddlewareForInternationalization**](/en/reference/errors/missing-middleware-for-internationalization/) Enabled manual internationalization routing without having a middleware.
+- [**InvalidI18nMiddlewareConfiguration**](/en/reference/errors/invalid-i18n-middleware-configuration/) Invalid internationalization middleware configuration
- [**CantRenderPage**](/en/reference/errors/cant-render-page/) Astro can't render the route.
- [**UnhandledRejection**](/en/reference/errors/unhandled-rejection/) Unhandled rejection
- [**i18nNotEnabled**](/en/reference/errors/i18n-not-enabled/) i18n Not Enabled
@@ -97,7 +98,7 @@ The following reference is a complete list of the errors you may encounter while
- [**ExperimentalFontsNotEnabled**](/en/reference/errors/experimental-fonts-not-enabled/) Experimental fonts are not enabled
- [**FontFamilyNotFound**](/en/reference/errors/font-family-not-found/) Font family not found
- [**FontBufferNotFound**](/en/reference/errors/font-buffer-not-found/) Font buffer not found
-- [**CspNotEnabled**](/en/reference/errors/csp-not-enabled/) CSP feature isn't enabled
+- [**UnavailableAstroGlobal**](/en/reference/errors/unavailable-astro-global/) Unavailable Astro global in getStaticPaths()
## CSS Errors
@@ -126,6 +127,9 @@ The following reference is a complete list of the errors you may encounter while
- [**GetEntryDeprecationError**](/en/reference/errors/get-entry-deprecation-error/) Invalid use of `getDataEntryById` or `getEntryBySlug` function.
- [**InvalidContentEntryFrontmatterError**](/en/reference/errors/invalid-content-entry-frontmatter-error/) Content entry frontmatter does not match schema.
- [**InvalidContentEntryDataError**](/en/reference/errors/invalid-content-entry-data-error/) Content entry data does not match schema.
+- [**LegacyContentConfigError**](/en/reference/errors/legacy-content-config-error/) Legacy content config file found.
+- [**ContentCollectionMissingLoader**](/en/reference/errors/content-collection-missing-loader/) Content collection is missing a `loader` definition.
+- [**ContentCollectionInvalidType**](/en/reference/errors/content-collection-invalid-type/) Content collection has an invalid `type` field.
- [**ContentLoaderReturnsInvalidId**](/en/reference/errors/content-loader-returns-invalid-id/) Content loader returned an entry with an invalid `id`.
- [**ContentEntryDataError**](/en/reference/errors/content-entry-data-error/) Content entry data does not match schema.
- [**LiveContentConfigError**](/en/reference/errors/live-content-config-error/) Error in live content config.
@@ -152,7 +156,4 @@ The following reference is a complete list of the errors you may encounter while
- [**SessionStorageInitError**](/en/reference/errors/session-storage-init-error/) Session storage could not be initialized.
- [**SessionStorageSaveError**](/en/reference/errors/session-storage-save-error/) Session data could not be saved.
-- [**SessionWithoutSupportedAdapterOutputError**](/en/reference/errors/session-without-supported-adapter-output-error/) Sessions cannot be used with an adapter that doesn't support server output.
-- [**SessionConfigMissingError**](/en/reference/errors/session-config-missing-error/) Session storage was enabled but not configured.
-- [**SessionConfigWithoutFlagError**](/en/reference/errors/session-config-without-flag-error/) Session flag not set
- [**CannotOptimizeSvg**](/en/reference/errors/cannot-optimize-svg/) Cannot optimize SVG
diff --git a/src/content/docs/en/reference/errors/astro-glob-no-match.mdx b/src/content/docs/en/reference/errors/astro-glob-no-match.mdx
index 0e440b87c3717..0e45b66b2a692 100644
--- a/src/content/docs/en/reference/errors/astro-glob-no-match.mdx
+++ b/src/content/docs/en/reference/errors/astro-glob-no-match.mdx
@@ -13,12 +13,14 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
+:::caution[Deprecated]
+This error was removed in Astro v6.0.0 along with the removal of `Astro.glob()`.
+:::
+
> **AstroGlobNoMatch**: `Astro.glob(GLOB_STR)` did not return any matching files.
## What went wrong?
`Astro.glob()` did not return any matching files. There might be a typo in the glob pattern.
-**See Also:**
-- [Astro.glob](/en/reference/api-reference/#astroglob)
diff --git a/src/content/docs/en/reference/errors/astro-glob-used-outside.mdx b/src/content/docs/en/reference/errors/astro-glob-used-outside.mdx
index 0046b3892b504..6aae23f28cf09 100644
--- a/src/content/docs/en/reference/errors/astro-glob-used-outside.mdx
+++ b/src/content/docs/en/reference/errors/astro-glob-used-outside.mdx
@@ -13,12 +13,14 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
+:::caution[Deprecated]
+This error was removed in Astro v6.0.0 along with the removal of `Astro.glob()`.
+:::
+
> **AstroGlobUsedOutside**: `Astro.glob(GLOB_STR)` can only be used in `.astro` files. `import.meta.glob(GLOB_STR)` can be used instead to achieve a similar result.
## What went wrong?
`Astro.glob()` can only be used in `.astro` files. You can use [`import.meta.glob()`](https://vite.dev/guide/features.html#glob-import) instead to achieve the same result.
-**See Also:**
-- [Astro.glob](/en/reference/api-reference/#astroglob)
diff --git a/src/content/docs/en/reference/errors/content-collection-invalid-type.mdx b/src/content/docs/en/reference/errors/content-collection-invalid-type.mdx
new file mode 100644
index 0000000000000..af57b12835bd7
--- /dev/null
+++ b/src/content/docs/en/reference/errors/content-collection-invalid-type.mdx
@@ -0,0 +1,24 @@
+---
+# NOTE: This file is auto-generated from 'scripts/error-docgen.mjs'
+# Do not make edits to it directly, they will be overwritten.
+# Instead, change this file: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+# Translators, please remove this note and the component.
+
+title: Content collection has an invalid type field.
+i18nReady: true
+githubURL: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+---
+import DontEditWarning from '~/components/DontEditWarning.astro'
+
+
+
+
+> **Example error message:**
+Invalid collection type "data". Remove the type from your collection definition in your content config file.
+
+## What went wrong?
+Content collections should no longer have a `type` field. Remove this field from your content config file.
+See the [Astro 6 migration guide](https://v6.docs.astro.build/en/guides/upgrade-to/v6/#removed-legacy-content-collections) for more information.
+
+
+
diff --git a/src/content/docs/en/reference/errors/content-collection-missing-loader.mdx b/src/content/docs/en/reference/errors/content-collection-missing-loader.mdx
new file mode 100644
index 0000000000000..81c3e4c3ecd7c
--- /dev/null
+++ b/src/content/docs/en/reference/errors/content-collection-missing-loader.mdx
@@ -0,0 +1,24 @@
+---
+# NOTE: This file is auto-generated from 'scripts/error-docgen.mjs'
+# Do not make edits to it directly, they will be overwritten.
+# Instead, change this file: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+# Translators, please remove this note and the component.
+
+title: Content collection is missing a loader definition.
+i18nReady: true
+githubURL: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+---
+import DontEditWarning from '~/components/DontEditWarning.astro'
+
+
+
+
+> **Example error message:**
+Collections must have a `loader` defined. Check your collection definitions in your content config file.
+
+## What went wrong?
+A content collection is missing a `loader` definition. Make sure that each collection in your content config file has a `loader`.
+See the [Content collections documentation](/en/guides/content-collections/) for more information.
+
+
+
diff --git a/src/content/docs/en/reference/errors/csp-not-enabled.mdx b/src/content/docs/en/reference/errors/csp-not-enabled.mdx
index 244ac07ec9f23..807ecdb17d936 100644
--- a/src/content/docs/en/reference/errors/csp-not-enabled.mdx
+++ b/src/content/docs/en/reference/errors/csp-not-enabled.mdx
@@ -13,7 +13,12 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
-> The `experimental.csp` configuration isn't enabled.
+:::caution[Deprecated]
+This error is from an older version of Astro and is no longer in use. If you are unable to upgrade your project to a more recent version, then you can consult [unmaintained snapshots of older documentation](/en/upgrade-astro/#older-docs-unmaintained) for assistance.
+:::
+
+
+> The `security.csp` configuration isn't enabled.
## What went wrong?
The CSP feature isn't enabled
diff --git a/src/content/docs/en/reference/errors/file-glob-not-supported.mdx b/src/content/docs/en/reference/errors/file-glob-not-supported.mdx
index 9918fdd56ccb5..6dffa461557a1 100644
--- a/src/content/docs/en/reference/errors/file-glob-not-supported.mdx
+++ b/src/content/docs/en/reference/errors/file-glob-not-supported.mdx
@@ -19,6 +19,6 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
The `file` loader must be passed a single local file. Glob patterns are not supported. Use the built-in `glob` loader to create entries from patterns of multiple local files.
**See Also:**
-- [Astro's built-in loaders](/en/guides/content-collections/#built-in-loaders)
+- [Astro's built-in `file()` loader](/en/reference/content-loader-reference/#file-loader)
diff --git a/src/content/docs/en/reference/errors/file-parser-not-found.mdx b/src/content/docs/en/reference/errors/file-parser-not-found.mdx
index fb1e433ea18fd..12441afb0ac61 100644
--- a/src/content/docs/en/reference/errors/file-parser-not-found.mdx
+++ b/src/content/docs/en/reference/errors/file-parser-not-found.mdx
@@ -19,6 +19,6 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
The `file` loader can’t determine which parser to use. Please provide a custom parser (e.g. `csv-parse`) to create a collection from your file type.
**See Also:**
-- [Passing a `parser` to the `file` loader](/en/guides/content-collections/#parser-function)
+- [Passing a `parser` to the `file` loader](https://v6.docs.astro.build/en/reference/content-loader-reference/#parser)
diff --git a/src/content/docs/en/reference/errors/get-entry-deprecation-error.mdx b/src/content/docs/en/reference/errors/get-entry-deprecation-error.mdx
index f6d9f05156c8e..72728c500b4ce 100644
--- a/src/content/docs/en/reference/errors/get-entry-deprecation-error.mdx
+++ b/src/content/docs/en/reference/errors/get-entry-deprecation-error.mdx
@@ -16,7 +16,7 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
> **GetEntryDeprecationError**: The `METHOD` function is deprecated and cannot be used to query the "COLLECTION" collection. Use `getEntry` instead.
## What went wrong?
-The `getDataEntryById` and `getEntryBySlug` functions are deprecated and cannot be used with content layer collections. Use the `getEntry` function instead.
+The `getDataEntryById` and `getEntryBySlug` functions are deprecated and cannot be used with content collections. Use the `getEntry` function instead.
diff --git a/src/content/docs/en/reference/errors/get-static-paths-invalid-route-param.mdx b/src/content/docs/en/reference/errors/get-static-paths-invalid-route-param.mdx
index cee383760cd45..f8eca93ebae3d 100644
--- a/src/content/docs/en/reference/errors/get-static-paths-invalid-route-param.mdx
+++ b/src/content/docs/en/reference/errors/get-static-paths-invalid-route-param.mdx
@@ -4,7 +4,7 @@
# Instead, change this file: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
# Translators, please remove this note and the component.
-title: Invalid value for getStaticPaths route parameter.
+title: Invalid route parameter returned by getStaticPaths().
i18nReady: true
githubURL: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
---
@@ -13,7 +13,7 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
-> **GetStaticPathsInvalidRouteParam**: Invalid getStaticPaths route parameter for `KEY`. Expected undefined, a string or a number, received `VALUE_TYPE` (`VALUE`)
+> **GetStaticPathsInvalidRouteParam**: Invalid `getStaticPaths()` route parameter for `KEY`. Expected a string or undefined, received `VALUE_TYPE` (`VALUE`)
## What went wrong?
Since `params` are encoded into the URL, only certain types are supported as values.
@@ -23,8 +23,9 @@ Since `params` are encoded into the URL, only certain types are supported as val
export async function getStaticPaths() {
return [
{ params: { id: '1' } } // Works
- { params: { id: 2 } } // Works
+ { params: { id: 2 } } // Does not work
{ params: { id: false } } // Does not work
+ { params: { id: [1, 2] } } // Does not work
];
}
---
@@ -36,8 +37,8 @@ In routes using [rest parameters](/en/guides/routing/#rest-parameters), `undefin
---
export async function getStaticPaths() {
return [
- { params: { id: 1 } } // /route/1
- { params: { id: 2 } } // /route/2
+ { params: { id: '1' } } // /route/1
+ { params: { id: '2' } } // /route/2
{ params: { id: undefined } } // /route/
];
}
diff --git a/src/content/docs/en/reference/errors/invalid-content-entry-data-error.mdx b/src/content/docs/en/reference/errors/invalid-content-entry-data-error.mdx
index 69f765d1235d5..c3e35af3641cd 100644
--- a/src/content/docs/en/reference/errors/invalid-content-entry-data-error.mdx
+++ b/src/content/docs/en/reference/errors/invalid-content-entry-data-error.mdx
@@ -14,7 +14,7 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
> **Example error message:**
-**blog** → **post** frontmatter does not match collection schema.
+**blog** → **post** data does not match collection schema.
"title" is required.
"date" must be a valid date.
diff --git a/src/content/docs/en/reference/errors/invalid-content-entry-frontmatter-error.mdx b/src/content/docs/en/reference/errors/invalid-content-entry-frontmatter-error.mdx
index 19c3ca122fd7d..909063a703402 100644
--- a/src/content/docs/en/reference/errors/invalid-content-entry-frontmatter-error.mdx
+++ b/src/content/docs/en/reference/errors/invalid-content-entry-frontmatter-error.mdx
@@ -13,6 +13,10 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
+:::caution[Deprecated]
+This error only applies to legacy content collections which were removed in Astro 6.
+:::
+
> **Example error message:**
**blog** → **post.md** frontmatter does not match collection schema.
"title" is required.
diff --git a/src/content/docs/en/reference/errors/invalid-glob.mdx b/src/content/docs/en/reference/errors/invalid-glob.mdx
index a6cfea8df3bac..d0452510ed6eb 100644
--- a/src/content/docs/en/reference/errors/invalid-glob.mdx
+++ b/src/content/docs/en/reference/errors/invalid-glob.mdx
@@ -13,6 +13,10 @@ import DontEditWarning from '~/components/DontEditWarning.astro'
+:::caution[Deprecated]
+This error was removed in Astro v6.0.0 along with the removal of `Astro.glob()`.
+:::
+
> **InvalidGlob**: Invalid glob pattern: `GLOB_PATTERN`. Glob patterns must start with './', '../' or '/'.
## What went wrong?
diff --git a/src/content/docs/en/reference/errors/invalid-i18n-middleware-configuration.mdx b/src/content/docs/en/reference/errors/invalid-i18n-middleware-configuration.mdx
new file mode 100644
index 0000000000000..aca71d0899e37
--- /dev/null
+++ b/src/content/docs/en/reference/errors/invalid-i18n-middleware-configuration.mdx
@@ -0,0 +1,22 @@
+---
+# NOTE: This file is auto-generated from 'scripts/error-docgen.mjs'
+# Do not make edits to it directly, they will be overwritten.
+# Instead, change this file: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+# Translators, please remove this note and the component.
+
+title: Invalid internationalization middleware configuration
+i18nReady: true
+githubURL: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+---
+import DontEditWarning from '~/components/DontEditWarning.astro'
+
+
+
+
+> **InvalidI18nMiddlewareConfiguration**: The option `redirectToDefaultLocale` can be enabled only when `prefixDefaultLocale` is also set to `true`, otherwise redirects might cause infinite loops. Enable the option `prefixDefaultLocale` to continue to use `redirectToDefaultLocale`, or ensure both are set to `false`.
+
+## What went wrong?
+An invalid i18n middleware configuration was detected.
+
+
+
diff --git a/src/content/docs/en/reference/errors/legacy-content-config-error.mdx b/src/content/docs/en/reference/errors/legacy-content-config-error.mdx
new file mode 100644
index 0000000000000..cc0ef66b4fadd
--- /dev/null
+++ b/src/content/docs/en/reference/errors/legacy-content-config-error.mdx
@@ -0,0 +1,24 @@
+---
+# NOTE: This file is auto-generated from 'scripts/error-docgen.mjs'
+# Do not make edits to it directly, they will be overwritten.
+# Instead, change this file: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+# Translators, please remove this note and the component.
+
+title: Legacy content config file found.
+i18nReady: true
+githubURL: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+---
+import DontEditWarning from '~/components/DontEditWarning.astro'
+
+
+
+
+> **Example error message:**
+Found legacy content config file in "src/content/config.ts". Please move this file to "src/content.config.ts" and ensure each collection has a loader defined.
+
+## What went wrong?
+A legacy content config file was found. Move the file to `src/content.config.ts` and update any collection definitions if needed.
+See the [Astro 6 migration guide](https://v6.docs.astro.build/en/guides/upgrade-to/v6/#removed-legacy-content-collections) for more information.
+
+
+
diff --git a/src/content/docs/en/reference/errors/live-content-config-error.mdx b/src/content/docs/en/reference/errors/live-content-config-error.mdx
index eee336c506e13..d7a82575cae63 100644
--- a/src/content/docs/en/reference/errors/live-content-config-error.mdx
+++ b/src/content/docs/en/reference/errors/live-content-config-error.mdx
@@ -20,6 +20,6 @@ The schema cannot be a function for live collections. Please use a schema object
Error in live content config.
**See Also:**
-- [Experimental live content](/en/reference/experimental-flags/live-content-collections/)
+- [Defining live content schemas](https://v6.docs.astro.build/en/reference/modules/astro-content/#schema-1)
diff --git a/src/content/docs/en/reference/errors/prerender-route-conflict.mdx b/src/content/docs/en/reference/errors/prerender-route-conflict.mdx
index f706b6021c0b3..a74901f5cee29 100644
--- a/src/content/docs/en/reference/errors/prerender-route-conflict.mdx
+++ b/src/content/docs/en/reference/errors/prerender-route-conflict.mdx
@@ -20,7 +20,7 @@ Two prerendered routes generate the same path, resulting in a collision.
A static path can only be generated by one route.
**See Also:**
-- [`getStaticPaths()`](/en/reference/routing-reference/#getstaticpaths)
-- [`params`](/en/reference/api-reference/#params)
+- [Route Priority Order](/en/guides/routing/#route-priority-order)
+- [`prerenderConflictBehavior`](/en/reference/configuration-reference/#prerenderconflictbehavior)
diff --git a/src/content/docs/en/reference/errors/unavailable-astro-global.mdx b/src/content/docs/en/reference/errors/unavailable-astro-global.mdx
new file mode 100644
index 0000000000000..f98a54926ee92
--- /dev/null
+++ b/src/content/docs/en/reference/errors/unavailable-astro-global.mdx
@@ -0,0 +1,22 @@
+---
+# NOTE: This file is auto-generated from 'scripts/error-docgen.mjs'
+# Do not make edits to it directly, they will be overwritten.
+# Instead, change this file: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+# Translators, please remove this note and the component.
+
+title: Unavailable Astro global in getStaticPaths()
+i18nReady: true
+githubURL: https://github.com/withastro/astro/blob/main/packages/astro/src/core/errors/errors-data.ts
+---
+import DontEditWarning from '~/components/DontEditWarning.astro'
+
+
+
+
+> The Astro global is not available in getStaticPaths().
+
+## What went wrong?
+Unavailable Astro global in getStaticPaths
+
+
+
diff --git a/src/content/docs/en/reference/experimental-flags/csp.mdx b/src/content/docs/en/reference/experimental-flags/csp.mdx
deleted file mode 100644
index 75d5e6b8b78b5..0000000000000
--- a/src/content/docs/en/reference/experimental-flags/csp.mdx
+++ /dev/null
@@ -1,497 +0,0 @@
----
-title: Experimental Content Security Policy (CSP)
-sidebar:
- label: Content Security Policy
-i18nReady: true
-tableOfContents:
- minHeadingLevel: 2
- maxHeadingLevel: 6
----
-
-import Since from '~/components/Since.astro'
-
-
-
-**Type:** `boolean | object`
-**Default:** `false`
-
-
-
-Enables support for [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP) to help minimize certain types of security threats by controlling which resources a document is allowed to load. This provides additional protection against [cross-site scripting (XSS)](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting) attacks.
-
-Enabling this feature adds additional security to **Astro's handling of processed and bundled scripts and styles** by default, and allows you to further configure these, and additional, content types.
-
-This experimental CSP feature has some limitations. Inline scripts are not supported out of the box, but you can [provide your own hashes](#hashes) for external and inline scripts. [Astro's view transitions](/en/guides/view-transitions/) using the ` ` are not supported, but you can [consider migrating to the browser native View Transition API](https://events-3bg.pages.dev/jotter/astro-view-transitions/) instead if you are not using Astro's enhancements to the native View Transitions and Navigation APIs.
-
-:::note
-Due to the nature of the Vite dev server, this feature isn't supported while working in `dev` mode. Instead, you can test this in your Astro project using `build` and `preview`.
-:::
-
-To enable this feature, add the experimental flag in your Astro config:
-
-```js title="astro.config.mjs" ins={4-6}
-import { defineConfig } from 'astro/config';
-
-export default defineConfig({
- experimental: {
- csp: true
- }
-});
-```
-
-When enabled, Astro will add a ` ` element inside the `` element of each page.
-
-This element will have the `http-equiv="content-security-policy"` attribute, and the `content` attribute will provide values for the `script-src` and `style-src` [directives](#directives) based on the script and styles used in the page.
-
-```html
-
-
-
-```
-
-## Configuration
-
-You can further customize the ` ` element by enabling this feature with a configuration object that includes additional options.
-
-### `algorithm`
-
-
-
-**Type:** `'SHA-256' | 'SHA-512' | 'SHA-384'`
-**Default:** `'SHA-256'`
-
-
-
-The [hash function](https://developer.mozilla.org/en-US/docs/Glossary/Hash_function) to use when generating the hashes of the styles and scripts emitted by Astro.
-
-```js title="astro.config.mjs"
-import { defineConfig } from 'astro/config';
-
-export default defineConfig({
- experimental: {
- csp: {
- algorithm: 'SHA-512'
- }
- }
-});
-```
-
-### `directives`
-
-
-
-**Type:** `CspDirective[]`
-**Default:** `[]`
-
-
-
-A list of [CSP directives](https://content-security-policy.com/#directive) that defines valid sources for specific content types.
-
-While Astro needs to control the `script-src` and `style-src` directives, it is possible to control other CSP directives using the `csp.directives` field. These directives are added to all pages. It accepts a list of type-safe directives:
-
-```js title="astro.config.mjs"
-import { defineConfig } from 'astro/config';
-
-export default defineConfig({
- experimental: {
- csp: {
- directives: [
- "default-src 'self'",
- "img-src 'self' https://images.cdn.example.com"
- ]
- }
- }
-});
-```
-
-After the build, the ` ` element will add your directives into the `content` value alongside Astro's default directives:
-
-```html
-
-```
-
-### `styleDirective` and `scriptDirective`
-
-
-
-**Type:** `object`
-**Default:** `{}`
-
-
-
-Configuration objects that allow you to override the default sources for the `style-src` and `script-src` directives with the [`resources`](#resources) property, or to provide additional [hashes](#hashes) to be rendered.
-
-These properties are added to all pages and **completely override Astro's default resources**, not add to them. Therefore, you must explicitly specify any default values that you want to be included.
-
-#### `resources`
-
-
-
-**Type:** `string[]`
-**Default:** `[]`
-
-
-
-A list of valid sources for the `script-src` and `style-src` directives, including [values for subclasses](#adding-values-for-subclasses).
-
-The `script-src` and `style-src` directives are handled by Astro by default, and use the `'self'` resource. This means that scripts and styles can only be downloaded by the current host (usually the current website).
-
-To override the default source, you can provide a list of resources instead. This will not include `'self'` by default, and must be included in this list if you wish to keep it. These resources are added to all pages.
-
-```js title="astro.config.mjs"
-import { defineConfig } from 'astro/config';
-
-export default defineConfig({
- experimental: {
- csp: {
- styleDirective: {
- resources: [
- "'self'",
- "https://styles.cdn.example.com"
- ]
- },
- scriptDirective: {
- resources: [
- "https://cdn.example.com"
- ]
- }
- }
- }
-});
-```
-
-After the build, the ` ` element will instead apply your sources to the `style-src` and `script-src` directives:
-
-```html
-
-
-
-```
-
-##### Adding values for subclasses
-
-You can also use this field to add valid values that belong to [`script-src-attr`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src-attr), [`script-src-elem`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src-elem), [`style-src-attr`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/style-src-attr) and [`style-src-elem`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/style-src-elem), such as `unsafe-hashes` and `unsafe-inline`.
-
-For example, if you have an external library that adds scripts or inline styles to some HTML elements of the page, you can add `unsafe-inline` to tell the browser that they are safe to render.
-
-```js title="astro.config.mjs"
-import { defineConfig } from 'astro/config';
-
-export default defineConfig({
- experimental: {
- csp: {
- styleDirective: {
- resources: [
- "'unsafe-inline'"
- ]
- },
- scriptDirective: {
- resources: [
- "'unsafe-inline'"
- ]
- }
- }
- }
-});
-```
-
-After the build, `style-src` and `script-src` directives will contain the `'unsafe-line'` resource:
-
-```html
-
-
-
-```
-
-##### Multiple resources
-
-When resources are inserted multiple times or from multiple sources (e.g. defined in your `csp` config and added using [the CSP runtime API](#runtime-apis)), Astro will remove any duplicates, and merge the new ones.
-
-In the following example, the directives `img-src https://global.cdn.example.org` and `default-src https://global.cdn.example.org` are set in `csp` configuration and will be applied to all pages.
-
-```js title="astro.config.mjs"
-export default defineConfig({
- experimental: {
- csp: {
- directives: [
- "img-src https://global.cdn.example.org",
- "default-src https://global.cdn.example.org"
- ]
- }
- }
-})
-```
-
-Additionally, on an individual page, the resources `img-src https://vendor.cdn.example.org/` and `default-src https://global.cdn.example.org/ https://vendor.cdn.example.org/` are added using the [Astro.csp.insertDirective](#cspinsertdirective).
-
-```astro title="src/pages/index.astro"
----
-Astro.csp.insertDirective("img-src https://vendor.cdn.example.org")
-Astro.csp.insertDirective("default-src https://global.cdn.example.org https://vendor.cdn.example.org")
----
-```
-
-During the build, the resources of the directives `img-src` and `default-src` for the `index.html` page are merged and deduplicated to create the appropriate headers.
-
-```html
-
-
-
-```
-
-
-#### `hashes`
-
-
-
-**Type:** `CspHash[]`
-**Default:** `[]`
-
-
-
-A list of additional hashes to be rendered.
-
-If you have external scripts or styles that aren't generated by Astro, or inline scripts, this configuration option allows you to provide additional hashes to be rendered.
-
-You must provide hashes that start with `sha384-`, `sha512-` or `sha256-`. Other values will cause a validation error. These hashes are added to all pages.
-
-```js title="astro.config.mjs"
-import { defineConfig } from 'astro/config';
-
-export default defineConfig({
- experimental: {
- csp: {
- styleDirective: {
- hashes: [
- "sha384-styleHash",
- "sha512-styleHash",
- "sha256-styleHash"
- ]
- },
- scriptDirective: {
- hashes: [
- "sha384-scriptHash",
- "sha512-scriptHash",
- "sha256-scriptHash"
- ]
- }
- }
- }
-});
-```
-
-After the build, the ` ` element will include your additional hashes in the `script-src` and `style-src` directives:
-
-```html
-
-```
-
-#### `strictDynamic`
-
-
-
-**Type:** `boolean`
-**Default:** `false`
-
-
-
-Enables [the `strict-dynamic` keyword](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP#the_strict-dynamic_keyword) to support the dynamic injection of scripts.
-
-```js title="astro.config.mjs"
-import { defineConfig } from 'astro/config';
-
-export default defineConfig({
- experimental: {
- csp: {
- scriptDirective: {
- strictDynamic: true
- }
- }
- }
-});
-```
-
-## Runtime APIs
-
-You can customize the ` ` element per page via runtime APIs available from the `Astro` global inside `.astro` components, or the `APIContext` type in endpoints and middleware.
-
-### `csp.insertDirective`
-
-
-
-**Type:** `(directive: CspDirective) => void`
-
-
-
-Adds a single directive to the current page. You can call this method multiple times to add additional directives.
-
-```astro
----
-Astro.csp.insertDirective("default-src 'self'");
-Astro.csp.insertDirective("img-src 'self' https://images.cdn.example.com");
----
-```
-
-After the build, the ` ` element for this individual page will incorporate your additional directives alongside the existing `script-src` and `style-src` directives:
-
-```html
-
-```
-
-### `csp.insertStyleResource`
-
-
-
-**Type:** `(resource: string) => void`
-
-
-
-Inserts a new resource to be used for the `style-src` directive.
-
-```astro
----
-Astro.csp.insertStyleResource("https://styles.cdn.example.com");
----
-```
-
-After the build, the ` ` element for this individual page will add your source to the default `style-src` directive:
-
-```html
-
-```
-
-### `csp.insertStyleHash`
-
-
-
-**Type:** `(hash: CspHash) => void`
-
-
-
-Adds a new hash to the `style-src` directive.
-
-```astro
----
-Astro.csp.insertStyleHash("sha512-styleHash");
----
-```
-
-After the build, the ` ` element for this individual page will add your hash to the default `style-src` directive:
-
-```html
-
-```
-
-### `csp.insertScriptResource`
-
-
-
-**Type:** `(resource: string) => void`
-
-
-
-Inserts a new valid source to be used for the `script-src` directive.
-
-```astro
----
-Astro.csp.insertScriptResource("https://scripts.cdn.example.com");
----
-```
-
-After the build, the ` ` element for this individual page will add your source to the default `script-src` directive:
-
-```html
-
-```
-
-### `csp.insertScriptHash`
-
-
-
-**Type:** `(hash: CspHash) => void`
-
-
-
-Adds a new hash to the `script-src` directive.
-
-```astro
----
-Astro.csp.insertScriptHash("sha512-scriptHash");
----
-```
-
-After the build, the ` ` element for this individual page will add your hash to the default `script-src` directive:
-
-```html
-
-```
diff --git a/src/content/docs/en/reference/experimental-flags/fail-on-prerender-conflict.mdx b/src/content/docs/en/reference/experimental-flags/fail-on-prerender-conflict.mdx
deleted file mode 100644
index d55f79acbf8af..0000000000000
--- a/src/content/docs/en/reference/experimental-flags/fail-on-prerender-conflict.mdx
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Experimental prerender conflict error
-sidebar:
- label: Prerender conflict error
-i18nReady: true
----
-
-import Since from '~/components/Since.astro'
-
-
-
-**Type:** `boolean`
-**Default:** `false`
-
-
-
-Turns prerender conflict warnings into errors during the build process.
-
-Astro currently warns you during the build about any conflicts between multiple dynamic routes that can result in the same output path. For example `/blog/[slug]` and `/blog/[...all]` both could try to prerender the `/blog/post-1` path. In such cases, Astro renders only the [highest priority route](/en/guides/routing/#route-priority-order) for the conflicting path. This allows your site to build successfully, although you may discover that some pages are rendered by unexpected routes.
-
-With this experimental flag set, the build will instead fail immediately with an error. This will require you to resolve any routing conflicts immediately, and will ensure that Astro is building your routes as you intend.
-
-To enable this behavior, add the `experimental.failOnPrerenderConflict` feature flag to your Astro config:
-
-```js title="astro.config.mjs" ins={4-6}
-import { defineConfig } from "astro/config"
-
-defineConfig({
- experimental: {
- failOnPrerenderConflict: true,
- },
-});
-```
-
-## Usage
-
-After enabling this flag, you may encounter errors about conflicting prerendered routes when you attempt to build your project. If this happens, you will need to update one or more of your [dynamic routes](/en/guides/routing/#dynamic-routes) to avoid ambiguous routing.
diff --git a/src/content/docs/en/reference/experimental-flags/heading-id-compat.mdx b/src/content/docs/en/reference/experimental-flags/heading-id-compat.mdx
deleted file mode 100644
index a19d1c9d01e49..0000000000000
--- a/src/content/docs/en/reference/experimental-flags/heading-id-compat.mdx
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: Experimental Markdown heading ID compatibility
-sidebar:
- label: Markdown heading ID compatibility
-i18nReady: true
----
-
-import Since from '~/components/Since.astro'
-
-
-
-**Type:** `boolean`
-**Default:** `false`
-
-
-
-The `experimental.headingIdCompat` flag makes the IDs generated by Astro for Markdown headings compatible with common platforms like GitHub and npm.
-
-To enable heading ID compatibility, set the flag to `true` in your Astro configuration:
-
-```js title="astro.config.mjs" ins={4-6}
-import { defineConfig } from "astro/config"
-
-export default defineConfig({
- experimental: {
- headingIdCompat: true,
- }
-})
-```
-
-## Usage
-
-This experimental flag allows you to retain the trailing hyphens on the end of IDs for Markdown headings ending in special characters, creating IDs compatible with those generated by other common platforms. It requires no specific usage and only affects how Astro generates the `id` for your headings written using Markdown syntax.
-
-Astro, like many platforms, uses the popular [`github-slugger`](https://github.com/Flet/github-slugger) package to convert the text content of a Markdown heading to a slug to use in IDs. This experimental flag allows you to omit Astro's additional default processing step that strips a trailing hyphen from the end of IDs for headings ending in special characters.
-
-For example, the following Markdown heading:
-
-```md
-## ` `
-```
-
-will generate the following HTML in Astro by default:
-
-```html "picture"
-<Picture />
-```
-
-Using `experimental.headingIdCompat`, the same Markdown will generate the following HTML, which is identical to that of platforms such as GitHub:
-
-```html "picture-"
-<Picture />
-```
-
-In a future major version, Astro will switch to use the compatible ID style by default, but you can opt in to the future behavior early using the `experimental.headingIdCompat` flag.
-
-## Usage with `rehypeHeadingIds` plugin
-
-If you are [using the `rehypeHeadingIds` plugin](/en/guides/markdown-content/#heading-ids-and-plugins) directly, opt in to the compatibility mode when passing the plugin in your Astro configuration:
-
-
-```js title="astro.config.mjs" {8}
-import { defineConfig } from 'astro/config';
-import { rehypeHeadingIds } from '@astrojs/markdown-remark';
-import { otherPluginThatReliesOnHeadingIDs } from 'some/plugin/source';
-
-export default defineConfig({
- markdown: {
- rehypePlugins: [
- [rehypeHeadingIds, { headingIdCompat: true }],
- otherPluginThatReliesOnHeadingIDs,
- ],
- },
-});
-```
diff --git a/src/content/docs/en/reference/experimental-flags/live-content-collections.mdx b/src/content/docs/en/reference/experimental-flags/live-content-collections.mdx
deleted file mode 100644
index 8e2b2356bd070..0000000000000
--- a/src/content/docs/en/reference/experimental-flags/live-content-collections.mdx
+++ /dev/null
@@ -1,635 +0,0 @@
----
-title: Experimental live content collections
-sidebar:
- label: Live content collections
-i18nReady: true
----
-
-import Since from '~/components/Since.astro';
-
-
-
-**Type:** `boolean`
-**Default:** `false`
-
-
-
-
-Enables support for live content collections in your project.
-
-Live content collections are a new type of [content collection](/en/guides/content-collections/) that fetch their data at runtime rather than build time. This allows you to access frequently updated data from CMSs, APIs, databases, or other sources using a unified API, without needing to rebuild your site when the data changes.
-
-## Basic usage
-
-To enable the feature, make sure you have an adapter configured for [on-demand rendering](/en/guides/on-demand-rendering/) and add the `experimental.liveContentCollections` flag to your `astro.config.mjs` file:
-
-```js title="astro.config.mjs"
-{
- experimental: {
- liveContentCollections: true,
- },
-}
-```
-
-Then create a new `src/live.config.ts` file (alongside your `src/content.config.ts` if you have one) to define your live collections with a [live loader](#creating-a-live-loader) and optionally a [schema](#using-zod-schemas) using the new `defineLiveCollection()` function from the `astro:content` module.
-
-```ts title="src/live.config.ts"
-import { defineLiveCollection } from 'astro:content';
-import { storeLoader } from '@mystore/astro-loader';
-
-const products = defineLiveCollection({
- loader: storeLoader({
- apiKey: process.env.STORE_API_KEY,
- endpoint: 'https://api.mystore.com/v1',
- }),
-});
-
-export const collections = { products };
-```
-
-You can then use the dedicated `getLiveCollection()` and `getLiveEntry()` functions to access your live data:
-
-```astro
----
-export const prerender = false; // Not needed in 'server' mode
-
-import { getLiveCollection, getLiveEntry } from 'astro:content';
-
-// Get all products
-const { entries: allProducts, error } = await getLiveCollection('products');
-if (error) {
- // Handle error appropriately
- console.error(error.message);
-}
-
-// Get products with a filter (if supported by your loader)
-const { entries: electronics } = await getLiveCollection('products', { category: 'electronics' });
-
-// Get a single product by ID (string syntax)
-const { entry: product, error: productError } = await getLiveEntry('products', Astro.params.id);
-if (productError) {
- return Astro.redirect('/404');
-}
-
-// Get a single product with a custom query (if supported by your loader) using a filter object
-const { entry: productBySlug } = await getLiveEntry('products', { slug: Astro.params.slug });
----
-```
-
-## When to use live content collections
-
-Live content collections are designed for data that changes frequently and needs to be up-to-date when a page is requested. Consider using them when:
-
-- **You need real-time information** (e.g. user-specific data, current stock levels)
-- **You want to avoid constant rebuilds** for content that changes often
-- **Your data updates frequently** (e.g. up-to-the-minute product inventory, prices, availability)
-- **You need to pass dynamic filters** to your data source based on user input or request parameters
-- **You're building preview functionality** for a CMS where editors need to see draft content immediately
-
-In contrast, use build-time content collections when:
-
-- **Performance is critical** and you want to pre-render data at build time
-- **Your data is relatively static** (e.g., blog posts, documentation, product descriptions)
-- **You want to benefit from build-time optimization** and caching
-- **You need to process MDX** or perform image optimization
-- **Your data can be fetched once and reused** across multiple builds
-
-See the [limitations of experimental live collections](#live-collection-limitations) and [key differences from build-time collections](#differences-from-build-time-collections) for more details on choosing between live and preloaded collections.
-
-## Using live collections
-
-You can [create your own live loaders](#creating-a-live-loader) for your data source, or you can use community loaders distributed as npm packages. Here's how you could use example CMS and e-commerce loaders:
-
-```ts title="src/live.config.ts"
-import { defineLiveCollection } from 'astro:content';
-import { cmsLoader } from '@example/cms-astro-loader';
-import { productLoader } from '@example/store-astro-loader';
-
-const articles = defineLiveCollection({
- loader: cmsLoader({
- apiKey: process.env.CMS_API_KEY,
- contentType: 'article',
- }),
-});
-
-const products = defineLiveCollection({
- loader: productLoader({
- apiKey: process.env.STORE_API_KEY,
- }),
-});
-
-export const collections = { articles, products };
-```
-
-You can then get content from both loaders with a unified API:
-
-```astro
----
-export const prerender = false; // Not needed in 'server' mode
-
-import { getLiveCollection, getLiveEntry } from 'astro:content';
-
-// Use loader-specific filters
-const { entries: draftArticles } = await getLiveCollection('articles', {
- status: 'draft',
- author: 'john-doe',
-});
-
-// Get a specific product by ID
-const { entry: product } = await getLiveEntry('products', Astro.params.slug);
----
-```
-
-### Error handling
-
-Live loaders can fail due to network issues, API errors, or validation problems. The API is designed to make error handling explicit.
-
-When you call `getLiveCollection()` or `getLiveEntry()`, the error will be one of:
-
-- The error type defined by the loader (if it returned an error)
-- A `LiveEntryNotFoundError` if the entry was not found
-- A `LiveCollectionValidationError` if the collection data does not match the expected schema
-- A `LiveCollectionCacheHintError` if the cache hint is invalid
-- A `LiveCollectionError` for other errors, such as uncaught errors thrown in the loader
-
-These errors have a static `is()` method that you can use to check the type of error at runtime:
-
-```astro "LiveEntryNotFoundError.is(error)"
----
-export const prerender = false; // Not needed in 'server' mode
-
-import { getLiveEntry, LiveEntryNotFoundError } from 'astro:content';
-
-const { entry, error } = await getLiveEntry('products', Astro.params.id);
-
-if (error) {
- if (LiveEntryNotFoundError.is(error)) {
- console.error(`Product not found: ${error.message}`);
- Astro.response.status = 404;
- } else {
- console.error(`Error loading product: ${error.message}`);
- return Astro.redirect('/500');
- }
-}
----
-```
-
-## Creating a live loader
-
-A live loader is an object with two methods: `loadCollection()` and `loadEntry()`. These methods should handle errors gracefully and return either data or an [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object.
-
-The standard pattern is to export a function that returns this loader object, allowing you to pass configuration options like API keys or endpoints.
-
-Here's a basic example:
-
-```ts title="myloader.ts"
-import type { LiveLoader } from 'astro/loaders';
-import { fetchFromCMS } from './cms-client.js';
-
-interface Article {
- id: string;
- title: string;
- content: string;
- author: string;
-}
-
-export function articleLoader(config: { apiKey: string }): LiveLoader {
- return {
- name: 'article-loader',
- loadCollection: async ({ filter }) => {
- try {
- const articles = await fetchFromCMS({
- apiKey: config.apiKey,
- type: 'article',
- filter,
- });
-
- return {
- entries: articles.map((article) => ({
- id: article.id,
- data: article,
- })),
- };
- } catch (error) {
- return {
- error: new Error(`Failed to load articles: ${error.message}`),
- };
- }
- },
- loadEntry: async ({ filter }) => {
- try {
- // filter will be { id: "some-id" } when called with a string
- const article = await fetchFromCMS({
- apiKey: config.apiKey,
- type: 'article',
- id: filter.id,
- });
-
- if (!article) {
- return {
- error: new Error('Article not found'),
- };
- }
-
- return {
- id: article.id,
- data: article,
- };
- } catch (error) {
- return {
- error: new Error(`Failed to load article: ${error.message}`),
- };
- }
- },
- };
-}
-```
-
-### Rendering content
-
-A loader can add support for directly rendered content by returning [a `rendered` property](/en/reference/content-loader-reference/#rendered) in the entry. This allows you to use [the `render()` function and ` ` component](/en/guides/content-collections/#rendering-body-content) to render the content directly in your pages.
-If the loader does not return a `rendered` property for an entry, the ` ` component will render nothing.
-
-```ts title="myloader.ts" {16-19}
-// ...
-export function articleLoader(config: { apiKey: string }): LiveLoader {
- return {
- name: 'article-loader',
- loadEntry: async ({ filter }) => {
- try {
- const article = await fetchFromCMS({
- apiKey: config.apiKey,
- type: 'article',
- id: filter.id,
- });
-
- return {
- id: article.id,
- data: article,
- rendered: {
- // Assuming the CMS returns HTML content
- html: article.htmlContent,
- },
- };
- } catch (error) {
- return {
- error: new Error(`Failed to load article: ${error.message}`),
- };
- }
- },
- // ...
- };
-}
-```
-
-You can then render both content and metadata from live collection entries in pages using the same method as built-time collections. You also have access to any [error returned by the live loader](#error-handling-in-loaders), for example, to rewrite to a 404 page when content cannot be displayed:
-
-```astro "render(entry)" " "
----
-export const prerender = false; // Not needed in 'server' mode
-
-import { getLiveEntry, render } from 'astro:content';
-const { entry, error } = await getLiveEntry('articles', Astro.params.id);
-if (error) {
- return Astro.rewrite('/404');
-}
-
-const { Content } = await render(entry);
----
-
-{entry.data.title}
-
-```
-
-### Error handling in loaders
-
-Loaders should handle all errors and return an [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) subclass for errors. You can create custom error types and use them for more specific error handling if needed. If an error is thrown in the loader, it will be caught and returned, wrapped in a `LiveCollectionError`. You can also create [custom error types](#custom-error-types) for proper typing.
-
-Astro will generate some errors itself, depending on the response from the loader:
-
-- If `loadEntry` returns `undefined`, Astro will return a `LiveEntryNotFoundError` to the user.
-- If a schema is defined for the collection and the data does not match the schema, Astro will return a `LiveCollectionValidationError`.
-- If the loader returns an invalid cache hint, Astro will return a `LiveCollectionCacheHintError`. The `cacheHint` field is optional, so if you do not have valid data to return, you can simply omit it.
-
-```ts title="my-loader.ts" {9-11}
-import type { LiveLoader } from 'astro/loaders';
-import { MyLoaderError } from './errors.js';
-
-export function myLoader(config): LiveLoader {
- return {
- name: 'my-loader',
- loadCollection: async ({ filter }) => {
- // Return your custom error type
- return {
- error: new MyLoaderError('Failed to load', 'LOAD_ERROR'),
- };
- },
- // ...
- };
-}
-```
-
-### Distributing your loader
-
-Loaders can be defined in your site or as a separate npm package. If you want to share your loader with the community, you can [publish it to NPM with the `astro-component` and `astro-loader` keywords](/en/reference/publish-to-npm/#packagejson-data).
-
-The loader should export a function that returns the `LiveLoader` object, allowing users to configure it with their own settings.
-
-## Type safety
-
-Like regular content collections, live collections can be typed to ensure type safety in your data. [Using Zod schemas](#using-zod-schemas) is supported, but not required to define types for live collections. Unlike preloaded collections defined at build time, live loaders can instead choose to pass generic types to the `LiveLoader` interface.
-You can define the types for your collection and entry data, as well as custom filter types for querying, and custom error types for error handling.
-
-### Type-safe data
-
-Live loaders can define types for the data they return. This allows TypeScript to provide type checking and autocompletion when working with the data in your components.
-
-```ts title="store-loader.ts" "LiveLoader" "type Product"
-import type { LiveLoader } from 'astro/loaders';
-import { fetchProduct, fetchCategory, type Product } from './store-client';
-
-export function storeLoader(): LiveLoader {
- // ...
-}
-```
-
-When you use `getLiveCollection()` or `getLiveEntry()`, TypeScript will infer the types based on the loader's definition:
-
-```astro
----
-export const prerender = false; // Not needed in 'server' mode
-
-import { getLiveEntry } from 'astro:content';
-const { entry: product } = await getLiveEntry('products', '123');
-// TypeScript knows product.data is of type Product
-console.log(product?.data.name);
----
-```
-
-### Type-safe filters
-
-Live loaders can define custom filter types for both `getLiveCollection()` and `getLiveEntry()`. This enables type-safe querying that matches your API's capabilities, making it easier for users to discover available filters and ensure they are used correctly. If you include JSDoc comments in your filter types, the user will see these in their IDE as hints when using the loader.
-
-```ts title="store-loader.ts" "EntryFilter, CollectionFilter" {6,8}
-import type { LiveLoader } from 'astro/loaders';
-import { fetchProduct, fetchCategory, type Product } from './store-client';
-
-interface CollectionFilter {
- category?: string;
- /** Minimum price to filter products */
- minPrice?: number;
- /** Maximum price to filter products */
- maxPrice?: number;
-}
-
-interface EntryFilter {
- /** Alias for `sku` */
- id?: string;
- slug?: string;
- sku?: string;
-}
-
-export function productLoader(config: {
- apiKey: string;
- endpoint: string;
-}): LiveLoader {
- return {
- name: 'product-loader',
- loadCollection: async ({ filter }) => {
- // filter is typed as CollectionFilter
- const data = await fetchCategory({
- apiKey: config.apiKey,
- category: filter?.category ?? 'all',
- minPrice: filter?.minPrice,
- maxPrice: filter?.maxPrice,
- });
-
- return {
- entries: data.products.map((product) => ({
- id: product.sku,
- data: product,
- })),
- };
- },
- loadEntry: async ({ filter }) => {
- // filter is typed as EntryFilter | { id: string }
- const product = await fetchProduct({
- apiKey: config.apiKey,
- slug: filter.slug,
- sku: filter.sku || filter.id,
- });
- if (!product) {
- return {
- error: new Error('Product not found'),
- };
- }
- return {
- id: product.sku,
- entry: product,
- };
- },
- };
-}
-```
-
-### Custom error types
-
-You can create custom error types for [errors returned by your loader](#error-handling-in-loaders) and pass them as a generic to get proper typing:
-
-```ts title="my-loader.ts"
-class MyLoaderError extends Error {
- constructor(
- message: string,
- public code?: string
- ) {
- super(message);
- this.name = 'MyLoaderError';
- }
-}
-
-export function myLoader(config): LiveLoader {
- return {
- name: 'my-loader',
- loadCollection: async ({ filter }) => {
- // Return your custom error type
- return {
- error: new MyLoaderError('Failed to load', 'LOAD_ERROR'),
- };
- },
- // ...
- };
-}
-```
-
-When you use `getLiveCollection()` or `getLiveEntry()`, TypeScript will infer the custom error type, allowing you to handle it appropriately:
-
-```astro
----
-export const prerender = false; // Not needed in 'server' mode
-
-import { getLiveEntry } from 'astro:content';
-
-const { entry, error } = await getLiveEntry('products', '123');
-
-if (error) {
- if (error.name === 'MyLoaderError') {
- console.error(`Loader error: ${error.message} (code: ${error.code})`);
- } else {
- console.error(`Unexpected error: ${error.message}`);
- }
- return Astro.rewrite('/500');
-}
----
-```
-
-## Using Zod schemas
-
-Just like with build-time collections, you can use [Zod schemas](/en/guides/content-collections/#defining-the-collection-schema) with live collections to validate and transform data at runtime. When you define a schema, it takes precedence over [the loader's types](#type-safe-data) when you query the collection:
-
-```ts title="src/live.config.ts"
-import { defineLiveCollection } from 'astro:content';
-import { z } from 'astro/zod';
-import { apiLoader } from './loaders/api-loader';
-
-const products = defineLiveCollection({
- loader: apiLoader({ endpoint: process.env.API_URL }),
- schema: z
- .object({
- id: z.string(),
- name: z.string(),
- price: z.number(),
- // Transform the API's category format
- category: z.string().transform((str) => str.toLowerCase().replace(/\s+/g, '-')),
- // Coerce the date to a Date object
- createdAt: z.coerce.date(),
- })
- .transform((data) => ({
- ...data,
- // Add a formatted price field
- displayPrice: `$${data.price.toFixed(2)}`,
- })),
-});
-
-export const collections = { products };
-```
-
-When using Zod schemas, validation errors are automatically caught and returned as `AstroError` objects:
-
-```astro
----
-export const prerender = false; // Not needed in 'server' mode
-
-import { getLiveEntry, LiveCollectionValidationError } from 'astro:content';
-
-const { entry, error } = await getLiveEntry('products', '123');
-
-// You can handle validation errors specifically
-if (LiveCollectionValidationError.is(error)) {
- console.error(error.message);
- return Astro.rewrite('/500');
-}
-
-// TypeScript knows entry.data matches your Zod schema, not the loader's type
-console.log(entry?.data.displayPrice); // e.g., "$29.99"
----
-```
-
-## Cache hints
-
-Live loaders can provide cache hints to help with response caching. You can use this data to send HTTP cache headers or otherwise inform your caching strategy.
-
-```ts title="my-loader.ts"
-import type { LiveLoader } from "astro/loaders";
-import { loadStoreProduct, loadStoreProducts, getLastModifiedDate } from "./store";
-import type { MyData } from "./types";
-
-export function myLoader(config): LiveLoader {
- return {
- name: 'cached-loader',
- loadCollection: async ({ filter }) => {
- const products = await loadStoreProducts(filter);
- return {
- entries: products.map((item) => ({
- id: item.id,
- data: item,
- // You can optionally provide cache hints for each entry
- cacheHint: {
- tags: [`product-${item.id}`, `category-${item.category}`],
- },
- })),
- cacheHint: {
- // All fields are optional, and are combined with each entry's cache hints
- // tags are merged from all entries
- // lastModified is the most recent lastModified of all entries and the collection
- lastModified: getLastModifiedDate(products),
- tags: ['products'],
- },
- };
- },
- loadEntry: async ({ filter }) => {
- const item = await loadStoreProduct(filter);
- return {
- id: item.id,
- data: item,
- cacheHint: {
- lastModified: new Date(item.lastModified),
- tags: [`product-${item.id}`, `category-${item.category}`],
- },
- };
- },
- };
-}
-```
-
-You can then use these hints in your pages:
-
-```astro
----
-export const prerender = false; // Not needed in 'server' mode
-
-import { getLiveEntry } from 'astro:content';
-
-const { entry, error, cacheHint } = await getLiveEntry('products', Astro.params.id);
-
-if (error) {
- return Astro.redirect('/404');
-}
-
-// Apply cache hints to response headers
-if (cacheHint?.tags) {
- Astro.response.headers.set('Cache-Tag', cacheHint.tags.join(','));
-}
-if (cacheHint?.lastModified) {
- Astro.response.headers.set('Last-Modified', cacheHint.lastModified.toUTCString());
-}
----
-
-{entry.data.name}
-{entry.data.description}
-```
-
-:::note
-Cache hints only provide values that can be used in other parts of your project and do not automatically cause the response to be cached by Astro. You can use them to create your own caching strategy, such as setting HTTP headers or using a CDN.
-:::
-
-## Live collection limitations
-
-Live content collections have some limitations compared to build-time collections:
-
-- **No MDX support**: MDX cannot be rendered at runtime
-- **No image optimization**: Images cannot be processed at runtime
-- **Performance considerations**: Data is fetched on each request (unless cached)
-- **No data store persistence**: Data is not saved to the content layer data store
-
-## Differences from build-time collections
-
-Live collections use a different API than current preloaded content collections. Key differences include:
-
-1. **Execution time**: Run at request time instead of build time
-2. **Configuration file**: Use `src/live.config.ts` instead of `src/content.config.ts`
-3. **Collection definition**: Use `defineLiveCollection()` instead of `defineCollection()`
-4. **Loader API**: Implement `loadCollection` and `loadEntry` methods instead of the `load` method
-5. **Data return**: Return data directly instead of storing in the data store
-6. **User-facing functions**: Use `getLiveCollection`/`getLiveEntry` instead of `getCollection`/`getEntry`
-
-For a complete overview and to give feedback on this experimental API, see the [Live Content collections RFC](https://github.com/withastro/roadmap/blob/feat/live-loaders/proposals/0055-live-content-loaders.md).
diff --git a/src/content/docs/en/reference/experimental-flags/preserve-scripts-order.mdx b/src/content/docs/en/reference/experimental-flags/preserve-scripts-order.mdx
deleted file mode 100644
index 429fb416c60d5..0000000000000
--- a/src/content/docs/en/reference/experimental-flags/preserve-scripts-order.mdx
+++ /dev/null
@@ -1,81 +0,0 @@
----
-title: Experimental preserve scripts order
-sidebar:
- label: Preserve scripts order
-i18nReady: true
----
-
-import Since from '~/components/Since.astro'
-
-
-
- **Type:** `boolean`
- **Default:** `false`
-
-
-
-Renders multiple `
-
-
-
-```
-
-After compiling, Astro's default behavior will create an inline style where `yellow` appears first, and then `red`. This means the `red` background is applied. Similarly with the two scripts, the word `world!` is logged first, and then `hello` second:
-
-```css
-body {background:#ff0} body {background:red}
-```
-
-```js
-console.log("world!")
-console.log("hello")
-```
-
-When `experimental.preserveScriptOrder` is set to `true`, the rendering order of `
-
-
-
-```
-
-Después de la compilación, el comportamiento predeterminado de Astro creará un estilo en línea donde `yellow` aparece primero, y luego `red`. Esto significa que se aplica el fondo `red`. De manera similar con los dos scripts, la palabra `world!` se registra primero, y luego `hello` en segundo lugar:
-
-```css
-body {background:#ff0} body {background:red}
-```
-
-```js
-console.log("world!")
-console.log("hello")
-```
-
-Cuando `experimental.preserveScriptOrder` se establece en `true`, el orden de renderizado de las etiquetas `
-
-
-
-```
-
-Après la compilation, le comportement par défaut d'Astro crée un style en ligne où `yellow` apparaît en premier, puis `red`. Cela signifie que l'arrière-plan `red` est appliqué. De même, avec les deux scripts, le mot `world!` est affiché en premier, suivi de `hello` :
-
-```css
-body {background:#ff0} body {background:red}
-```
-
-```js
-console.log("world!")
-console.log("hello")
-```
-
-Lorsque `experimental.preserveScriptOrder` est définie sur `true`, l'ordre de restitution des balises `
-
-
-
-```
-
-컴파일 후 Astro의 기본 동작은 `yellow`가 먼저 나타나고 `red`가 다음에 나타나는 인라인 스타일을 생성합니다. 이는 `red` 배경이 적용됨을 의미합니다. 두 스크립트의 경우 `world!`가 먼저 기록되고 `hello`가 다음에 기록됩니다.
-
-```css
-body {background:#ff0} body {background:red}
-```
-
-```js
-console.log("world!")
-console.log("hello")
-```
-
-`experimental.preserveScriptOrder`가 `true`로 설정되면 `
-
-
-
-```
-
-在编译后,Astro 的默认行为会创建一个内联样式,其中 `yellow` 首先出现,然后是 `red`。这意味着最终应用的是 `red` 背景。类似地,对于两个脚本,会先打印 `world!`,然后是 `hello`:
-
-```css
-body {background:#ff0} body {background:red}
-```
-
-```js
-console.log("world!")
-console.log("hello")
-```
-
-当 `experimental.preserveScriptOrder` 设置为 `true` 时,`