From 530c68fe26cdae5bad9da9a8165508777c8081f4 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Sat, 18 Oct 2025 13:23:06 +0000 Subject: [PATCH 01/41] remove legacy note, start to rewrite introduction --- src/content/docs/en/guides/content-collections.mdx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index 7e0c62721112d..d00ad29133c5e 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -13,11 +13,8 @@ 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. -:::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. -::: +Whether your content lives locally in your project, is stored remotely, or is even fetched from a live, frequently-updating source, Astro provides performant, scalable APIs to load, query, and render your content. ## What are Content Collections? From 7a36689fbd6550a2f250a4e2aac32cc14a3be67d Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Sat, 18 Oct 2025 14:39:57 +0000 Subject: [PATCH 02/41] what are content collections? --- src/content/docs/en/guides/content-collections.mdx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index d00ad29133c5e..c9026a1dd7d6f 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -18,9 +18,11 @@ Whether your content lives locally in your project, is stored remotely, or is ev ## 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. +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. Individual items within a collection are called **entries**. -Collections stored locally in your project or on your filesystem can have entries of Markdown, MDX, Markdoc, YAML, TOML, or JSON files: +A [collection schema](#defining-the-collection-schema) allows you to define the expected shape of each entry, providing type safety, autocomplete, and validation in your editor. + +Collections use a `loader` to retrieve your content. Collections stored locally in your project or on your filesystem can use one of [Astro's built-in loaders](#built-in-loaders) to fetch data from Markdown, MDX, Markdoc, YAML, TOML, or JSON files: - src/ @@ -32,7 +34,7 @@ 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. +With [community-built loaders](https://astro.build/integrations/?search=&categories%5B%5D=loaders) or by [building a custom collection loader](#building-a-custom-loader) yourself, you can fetch remote data from any external source, such as a CMS, database, or headless payment system. ## TypeScript configuration for collections From a0940ae627b454a4914357ae10fa131d014d3d2f Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Sat, 18 Oct 2025 15:09:04 +0000 Subject: [PATCH 03/41] types of collections section --- src/content/docs/en/guides/content-collections.mdx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index c9026a1dd7d6f..9fd8b1af24051 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -36,6 +36,16 @@ Collections use a `loader` to retrieve your content. Collections stored locally With [community-built loaders](https://astro.build/integrations/?search=&categories%5B%5D=loaders) or by [building a custom collection loader](#building-a-custom-loader) yourself, you can fetch remote data from any external source, such as a CMS, database, or headless payment system. +## Types of collections + +**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. + +**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. Additionally, neither MDX entries nor image optimization are currently supported. + +We suggest using content collections whenever possible, and using live collections when your content needs updating in real time and the performance tradeoffs are acceptable. + +Both types of collection use similar APIs (e.g. `getEntry()` and `getLiveEntry()`) 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. + ## 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`: From 0e5b4498e823ac981a92e0b3fc96ff3ff3bf8ae9 Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> Date: Sat, 18 Oct 2025 12:33:23 -0300 Subject: [PATCH 04/41] more about collections --- .../docs/en/guides/content-collections.mdx | 84 ++++++++++++++----- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index 9fd8b1af24051..ee7e30b24130b 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -36,6 +36,33 @@ Collections use a `loader` to retrieve your content. Collections stored locally With [community-built loaders](https://astro.build/integrations/?search=&categories%5B%5D=loaders) or by [building a custom collection loader](#building-a-custom-loader) yourself, you can fetch remote data from any external source, such as a CMS, database, or headless payment system. +### When to create a collection + +You can create a collection 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. +- 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. + +Define your data 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 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. + +### 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. + ## Types of collections **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. @@ -46,6 +73,28 @@ We suggest using content collections whenever possible, and using live collectio Both types of collection use similar APIs (e.g. `getEntry()` and `getLiveEntry()`) 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. +### Build-time content collections + +For the best performance and scalability, 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. + +### 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. + +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. + ## 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`: @@ -578,30 +627,23 @@ const { Content } = await render(post); 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! ::: -## 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: +### Live collection limitations -- 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. +Live content collections have some limitations compared to build-time collections: -### When not to create a collection +- **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 -Collections provide excellent structure, safety, and organization when you have **multiple pieces of content that must share the same properties**. +### Differences from build-time collections -Collections **may not be your solution** if: +Live collections use a different API than build-time content collections. Key differences include: -- 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/). +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` From cd362bd52f33925dc442ef566995f4b1ef8968ac Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Sun, 19 Oct 2025 19:18:21 +0000 Subject: [PATCH 05/41] attempt at redoing the loader section --- .../docs/en/guides/content-collections.mdx | 401 +++++++++++++++--- 1 file changed, 340 insertions(+), 61 deletions(-) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index ee7e30b24130b..b5e11373b29f0 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -22,7 +22,7 @@ You can define a **collection** from a set of data that is structurally similar. A [collection schema](#defining-the-collection-schema) allows you to define the expected shape of each entry, providing type safety, autocomplete, and validation in your editor. -Collections use a `loader` to retrieve your content. Collections stored locally in your project or on your filesystem can use one of [Astro's built-in loaders](#built-in-loaders) to fetch data from Markdown, MDX, Markdoc, YAML, TOML, or JSON files: +Collections use a [loader](#collection-loaders) to retrieve your content. Collections stored locally in your project or on your filesystem can use one of Astro's built-in loaders to fetch data from Markdown, MDX, Markdoc, YAML, TOML, or JSON files: - src/ @@ -65,13 +65,13 @@ Collections **may not be your solution** if: ## Types of collections -**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. +**[Content collections](#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. -**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. Additionally, neither MDX entries nor image optimization are currently supported. +**[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. -We suggest using content collections whenever possible, and using live collections when your content needs updating in real time and the performance tradeoffs are acceptable. +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. You may have both kinds of collections 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 collection use similar APIs (e.g. `getEntry()` and `getLiveEntry()`) 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. +Both types of collections use similar APIs (e.g. `getEntry()` and `getLiveEntry()`) 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. ### Build-time content collections @@ -83,6 +83,24 @@ For the best performance and scalability, use build-time content collections whe - **You need to process MDX** or perform image optimization. - **Your data can be fetched once and reused** across multiple builds. +Build-time content collections are defined in `src/content.config.ts` (`.js` and `.mjs` extensions are also supported) using `defineCollection()` and then exported for use in your project. + +Each individual collection configures: +- a `loader` for a data source (required) +- a `schema` for type safety (optional, but highly recommended!) + +```ts title="src/content.config.ts" +import { defineCollection, z } from 'astro:content'; +import { glob } from 'astro/loaders'; + +const blog = defineCollection({ + loader: /* ... */ + schema: /* ... */ +}); + +export const collections = { blog }; +``` + ### 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: @@ -95,6 +113,25 @@ Live content collections are designed for data that changes frequently and needs 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. +Make sure you have an adapter configured for [on-demand rendering](/en/guides/on-demand-rendering/), then define your live collections in `src/live.config.ts` (alongside your `src/content.config.ts` for build-time collections, if you have one). + +Like build-time content collections, live collections can be typed to ensure type safety in your data [using Zod schemas](#using-zod-schemas). But, this is not required to [define types for live collections](). Unlike collections defined at build time, live loaders can instead choose to pass generic types to the `LiveLoader` interface. + +```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 const collections = { products }; +``` + ## 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`: @@ -110,75 +147,49 @@ Content collections rely on TypeScript to provide Zod validation, Intellisense a } ``` -## Defining Collections +## Build time collection loaders -Individual collections use `defineCollection()` to configure: -- a `loader` for a data source (required) -- a `schema` for type safety (optional, but highly recommended!) +A loader allows you to fetch your content collections data, whether stored locally in your project or remotely. -### The collection config file +Astro provides two built-in loader functions (`glob()` and `file()`) for fetching your local content at build time, as well as access to the [Content Loader API](/en/reference/content-loader-reference/) to construct your own loaders to fetch remote data. -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: +### The `glob()` loader -```ts title="src/content.config.ts" -// 1. Import utilities from `astro:content` -import { defineCollection, z } from 'astro:content'; +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. If you store your content locally, such as a directory of blog posts, then the `glob()` loader is all you need to access your content. -// 2. Import loader(s) +This loader 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 each entry in your content collection is its own single file. + +```ts title="src/content.config.ts" {5,9} +import { defineCollection, z } from 'astro:content'; import { glob, file } from 'astro/loaders'; -// 3. Define your collection(s) -const blog = defineCollection({ /* ... */ }); -const dogs = defineCollection({ /* ... */ }); +const blog = defineCollection({ + loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }), + schema: /* ... */ +}); -// 4. Export a single `collections` object to register your collection(s) -export const collections = { blog, dogs }; +export const collections = { blog }; ``` -### Defining the collection `loader` - -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. +### The `file()` loader -#### Built-in loaders +The [`file()` loader](/en/reference/content-loader-reference/#file-loader) creates multiple entries from a single local file. This is useful if your content is stored as multiple objects within a single JSON or TOML file. -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. +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) 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 [`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. - -```ts title="src/content.config.ts" {5,9} +```ts title="src/content.config.ts" import { defineCollection, z } from 'astro:content'; -import { glob, file } from 'astro/loaders'; // Not available with legacy API +import { file } from 'astro/loaders'; -const blog = defineCollection({ - loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }), - schema: /* ... */ -}); 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 = { blog, dogs, probes }; +export const collections = { dogs }; ``` -##### `parser` function +#### `parser` function 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. @@ -196,7 +207,7 @@ const cats = defineCollection({ }); ``` -###### 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: @@ -215,7 +226,7 @@ const cats = defineCollection({ }); ``` -#### Building a custom loader +### Custom build-time loaders You can build a custom loader to fetch remote content from any data source, such as a CMS, a database, or an API endpoint. @@ -225,7 +236,7 @@ Using a loader to fetch your data will automatically create a collection from yo Find community-built and third-party loaders in the [Astro integrations directory](https://astro.build/integrations/?search=&categories%5B%5D=loaders). ::: -##### Inline loaders +#### Inline build-time loaders You can define a loader inline, inside your collection, as an async function that returns an array of entries. @@ -248,15 +259,232 @@ const countries = defineCollection({ The returned entries are stored in the collection and can be queried using the `getCollection()` and `getEntry()` functions. -##### Loader objects +#### Loader objects -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. +For more control over the loading process, you can use the Content Loader API to create a [loader object](/en/reference/content-loader-reference/#object-loaders). 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. 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. -### Defining the collection schema +## 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}`), + }; + } + }, + }; +} +``` + +### Defining data types + +Like regular content collections, live collections can be typed to ensure type safety in your data. [Using Zod schemas](#using-zod-schemas-with-live-collections) 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. + +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); +--- +``` + +### 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, + entry: product, + }; + }, + }; +} +``` + +### Creating live loader 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'); +} +--- +``` + +## 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. @@ -293,7 +521,7 @@ 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. @@ -329,13 +557,64 @@ defineCollection({ }) ``` +### Using Zod schemas with live collections + +Just like with build-time collections, you can use Zod schemas 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 { 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, 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" +--- +``` + See [Zod's README](https://github.com/colinhacks/zod) for complete documentation on how Zod works and what features are available. -##### Zod schema methods +#### Zod schema methods All [Zod schema methods](https://zod.dev/?id=schema-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. From cc8cd1b9bd16709cad5c32bcde9210599c7d206f Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Sun, 19 Oct 2025 19:40:38 +0000 Subject: [PATCH 06/41] more section heading work --- .../docs/en/guides/content-collections.mdx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index b5e11373b29f0..bc7b951943a4d 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -101,6 +101,10 @@ const blog = defineCollection({ export const collections = { blog }; ``` +You can then use the dedicated `getCollection()` and `getEntry()` functions to [query your content collections data](#querying-build-time-collections) and render your content. + + + ### 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: @@ -132,6 +136,9 @@ const products = defineLiveCollection({ export const collections = { products }; ``` +You can then use the dedicated `getLiveCollection()` and `getLiveEntry()` functions to [access your live data](#accessing-live-data). + + ## 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`: @@ -684,7 +691,7 @@ Your blog post content here. } ``` -## Querying Collections +## Querying build-time collections Astro provides helper functions to query a collection and return one (or more) content entries. @@ -738,7 +745,7 @@ const posts = await getCollection('blog'); ))} ``` -#### Rendering body content +### 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. @@ -757,7 +764,7 @@ const { Content, headings } = await render(entry); ``` -#### Passing content as props +### Passing content as props A component can also pass an entire collection entry as a prop. @@ -837,6 +844,10 @@ const relatedPosts = await getEntries(blogPost.data.relatedPosts); ))} ``` +## Accessing live data + +Basically, the querying section but for live collections + ## 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. From 20150cf16f56e8428f49bd8c7eabfec124648ec5 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Sun, 19 Oct 2025 19:49:07 +0000 Subject: [PATCH 07/41] more sections added to incorporate and organize live collections --- .../docs/en/guides/content-collections.mdx | 241 +++++++++++++++++- 1 file changed, 240 insertions(+), 1 deletion(-) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index bc7b951943a4d..ba3d1ff243d72 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -441,6 +441,35 @@ export function productLoader(config: { } ``` +### 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'), + }; + }, + // ... + }; +} +``` + + ### Creating live loader 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: @@ -491,6 +520,86 @@ if (error) { --- ``` +### 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" +export function myLoader(config): LiveLoader { + return { + name: 'cached-loader', + loadCollection: async ({ filter }) => { + // ... fetch data + return { + entries: data.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 + // maxAge is the shortest maxAge of all entries and the collection + // lastModified is the most recent lastModified of all entries and the collection + lastModified: new Date(item.lastModified), + tags: ['products'], + maxAge: 300, // 5 minutes + }, + }; + }, + loadEntry: async ({ filter }) => { + // ... fetch single item + return { + id: item.id, + data: item, + cacheHint: { + lastModified: new Date(item.lastModified), + tags: [`product-${item.id}`, `category-${item.category}`], + maxAge: 3600, // 1 hour + }, + }; + }, + }; +} +``` + +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?.maxAge) { + Astro.response.headers.set('Cache-Control', `s-maxage=${cacheHint.maxAge}`); +} +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. +::: + ## 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. @@ -846,7 +955,137 @@ const relatedPosts = await getEntries(blogPost.data.relatedPosts); ## Accessing live data -Basically, the querying section but for 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'); + } +} +--- +``` + +### 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}

+ +``` ## Generating Routes from Content From 706d7d1e979261b6eae2682ea4ffc1ed02cf5926 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Mon, 20 Oct 2025 14:10:27 +0000 Subject: [PATCH 08/41] more attention to "quick start" of easy case, streamlining Accessing Live Data to focus on using content (not loader building) --- .../docs/en/guides/content-collections.mdx | 131 ++++++------------ 1 file changed, 46 insertions(+), 85 deletions(-) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index ba3d1ff243d72..ca9d36f98e408 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -77,7 +77,7 @@ Both types of collections use similar APIs (e.g. `getEntry()` and `getLiveEntry( For the best performance and scalability, use build-time content collections when: -- **Performance is critical** and you want to pre-render data at build time. +- **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. @@ -86,10 +86,11 @@ For the best performance and scalability, use build-time content collections whe Build-time content collections are defined in `src/content.config.ts` (`.js` and `.mjs` extensions are also supported) using `defineCollection()` and then exported for use in your project. Each individual collection configures: -- a `loader` for a data source (required) -- a `schema` for type safety (optional, but highly recommended!) +- [a `loader`](#build-time-collection-loaders) for a data source (required) +- [a `schema`](#defining-the-collection-schema) for type safety (optional, but highly recommended!) ```ts title="src/content.config.ts" +// Define build-time collections with a loader and a schema import { defineCollection, z } from 'astro:content'; import { glob } from 'astro/loaders'; @@ -103,7 +104,9 @@ export const collections = { blog }; You can then use the dedicated `getCollection()` and `getEntry()` functions to [query your content collections data](#querying-build-time-collections) and render your content. - +:::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 Markdown or MDX blog posts. +::: ### Live content collections @@ -117,9 +120,17 @@ Live content collections are designed for data that changes frequently and needs 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. -Make sure you have an adapter configured for [on-demand rendering](/en/guides/on-demand-rendering/), then define your live collections in `src/live.config.ts` (alongside your `src/content.config.ts` for build-time collections, if you have one). +Make sure you have an adapter configured for [on-demand rendering](/en/guides/on-demand-rendering/), then define your live collections in `src/live.config.ts` (separate from your `src/content.config.ts` for build-time collections, if you have one). + +Each individual collection configures: +- a `loader` for your data source (required) +- a `schema` 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. + +Live loaders can provide type safety by passing 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. -Like build-time content collections, live collections can be typed to ensure type safety in your data [using Zod schemas](#using-zod-schemas). But, this is not required to [define types for live collections](). Unlike collections defined at build time, live loaders can instead choose to pass generic types to the `LiveLoader` interface. +You can instead provide type safety by [using a Zod schema](#using-zod-schemas-with-live-collections) like build-time collections do. Defining a `schema` 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 @@ -136,8 +147,7 @@ const products = defineLiveCollection({ export const collections = { products }; ``` -You can then use the dedicated `getLiveCollection()` and `getLiveEntry()` functions to [access your live data](#accessing-live-data). - +You can then use the dedicated `getLiveCollection()` and `getLiveEntry()` functions to [access your live data](#accessing-live-data) and render your content. ## TypeScript configuration for collections @@ -955,30 +965,14 @@ const relatedPosts = await getEntries(blogPost.data.relatedPosts); ## Accessing live data -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', - }), -}); +Astro provides helper functions to query a live collection and return one (or more) content entries. -const products = defineLiveCollection({ - loader: productLoader({ - apiKey: process.env.STORE_API_KEY, - }), -}); +- [`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. -export const collections = { articles, products }; -``` +These return entries with a unique `id`, and `data` object with all defined properties from the data 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 then get content from both loaders with a unified API: +You can use these functions to access your live data, passing the name of the collection and optionally filtering conditions. ```astro --- @@ -997,6 +991,29 @@ const { entry: product } = await getLiveEntry('products', Astro.params.slug); --- ``` +### 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, using the same method as build-time collections. If the loader does not return a `rendered` property for an entry, the `` component will render nothing. + +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 Live loaders can fail due to network issues, API errors, or validation problems. The API is designed to make error handling explicit. @@ -1031,62 +1048,6 @@ if (error) { --- ``` -### 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}

- -``` - ## 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. From e3a03df0f3161e7381407ef1b480eefadc45c856 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Wed, 22 Oct 2025 07:21:37 +0000 Subject: [PATCH 09/41] incorporate current updates to content collections guide page --- src/content/docs/en/guides/content-collections.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index ca9d36f98e408..853adc8627a75 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -883,6 +883,8 @@ const { Content, headings } = await render(entry); ``` +When working with MDX entries, you can also [pass your own components to ``](/en/guides/integrations-guide/mdx/#passing-components-to-mdx-content) to replace HTML elements with custom alternatives. + ### Passing content as props A component can also pass an entire collection entry as a prop. From ff9926f30492c543d67992dfb4e181002e625dbb Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Wed, 22 Oct 2025 11:15:13 +0000 Subject: [PATCH 10/41] way more links to make happy paths, and attempts to make loader content seem less overwhelming --- .../docs/en/guides/content-collections.mdx | 163 ++++++++++++------ 1 file changed, 110 insertions(+), 53 deletions(-) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index 853adc8627a75..1e6c990636c70 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: 5 --- import { FileTree, CardGrid, LinkCard, Steps } from '@astrojs/starlight/components'; import Since from '~/components/Since.astro' @@ -22,7 +25,9 @@ You can define a **collection** from a set of data that is structurally similar. A [collection schema](#defining-the-collection-schema) allows you to define the expected shape of each entry, providing type safety, autocomplete, and validation in your editor. -Collections use a [loader](#collection-loaders) to retrieve your content. Collections stored locally in your project or on your filesystem can use one of Astro's built-in loaders to fetch data from Markdown, MDX, Markdoc, YAML, TOML, or JSON files: +Both [build-time collections](#build-time-content-collections) and [live updating collections](#live-content-collections) use a `loader` to retrieve your content from wherever it is stored. + +Collections stored locally in your project or on your filesystem can use one of Astro's [built-in build-time loaders](#build-time-collection-loaders) to fetch data from Markdown, MDX, Markdoc, YAML, TOML, or JSON files: - src/ @@ -34,7 +39,7 @@ Collections use a [loader](#collection-loaders) to retrieve your content. Collec - authors.json a single file containing all collection entries -With [community-built loaders](https://astro.build/integrations/?search=&categories%5B%5D=loaders) or by [building a custom collection loader](#building-a-custom-loader) yourself, you can fetch remote data from any external source, such as a CMS, database, or headless payment system. +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 [creating a 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. ### When to create a collection @@ -65,11 +70,13 @@ Collections **may not be your solution** if: ## Types of collections -**[Content collections](#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. +**[Build-time content collections](#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. **[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. -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. You may have both kinds of collections 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. +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. + +You may have both kinds of collections 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. `getEntry()` and `getLiveEntry()`) 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. @@ -123,14 +130,12 @@ See the [limitations of experimental live collections](#live-collection-limitati Make sure you have an adapter configured for [on-demand rendering](/en/guides/on-demand-rendering/), then define your live collections in `src/live.config.ts` (separate from your `src/content.config.ts` for build-time collections, if you have one). Each individual collection configures: -- a `loader` for your data source (required) +- a `loader` for your data source, and optionally for type safety (required) - a `schema` 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. -Live loaders can provide type safety by passing 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. - -You can instead provide type safety by [using a Zod schema](#using-zod-schemas-with-live-collections) like build-time collections do. Defining a `schema` is optional. However, if you provide one, it will take precedence over the live loader's types. +You can optionally [include type safety your live loaders](#type-safety-in-live-loaders). 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 @@ -247,7 +252,7 @@ const cats = defineCollection({ 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. +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](#querying-build-time-collections), 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). @@ -280,7 +285,7 @@ The returned entries are stored in the collection and can be queried using the ` For more control over the loading process, you can use the Content Loader API to create a [loader object](/en/reference/content-loader-reference/#object-loaders). 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. -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. @@ -355,7 +360,81 @@ export function articleLoader(config: { apiKey: string }): LiveLoader
{ } ``` -### Defining data types +### Providing rendered 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](#rendering-content) in pages using the same method as built-time collections. + +### Error handling in live 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'), + }; + }, + // ... + }; +} +``` + +### Type safety in live loaders + +You can provide type safety for live collections by [using a Zod schema](#using-zod-schemas-with-live-collections) like you do in build-time collections. + +Live loaders can also provide their own type safety by passing generic types to the `LiveLoader` interface. You can [define the types](#defining-data-types) for your collection and entry data, as well as [custom filter types](#defining-custom-filter-types) for querying, and [custom error types](#creating-live-loader-error-types) for error handling in the live loader itself. + +#### Defining data types Like regular content collections, live collections can be typed to ensure type safety in your data. [Using Zod schemas](#using-zod-schemas-with-live-collections) 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. @@ -385,7 +464,7 @@ console.log(product?.data.name); --- ``` -### Defining custom filter types +#### 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. @@ -451,38 +530,9 @@ export function productLoader(config: { } ``` -### 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'), - }; - }, - // ... - }; -} -``` - +#### Creating live loader error types -### Creating live loader 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: +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" class MyLoaderError extends Error { @@ -610,6 +660,13 @@ if (cacheHint?.lastModified) { 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 `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. + ## 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. @@ -651,7 +708,7 @@ export const collections = { blog, dogs }; 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. -To use Zod in Astro, import the `z` utility from `"astro:content"`. 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:content"`. This is a re-export of the Zod library, and it supports all of the features of Zod 3. ```ts // Example: A cheatsheet of many common Zod datatypes @@ -683,9 +740,13 @@ defineCollection({ }) ``` +#### Zod schema methods + +All [Zod schema methods](https://zod.dev/?id=schema-methods) (e.g. `.parse()`, `.transform()`) are available, with some limitations. Notably, performing custom validation checks on images using `image().refine()` is unsupported. + ### Using Zod schemas with live collections -Just like with build-time collections, you can use Zod schemas 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: +Just like with build-time collections, you can use Zod schemas with live collections to validate and transform data at runtime. When you define a schema, it takes precedence over [the loader's types](#type-safety-in-live-loaders) when you query the collection: ```ts title="src/live.config.ts" import { z, defineLiveCollection } from 'astro:content'; @@ -736,15 +797,11 @@ 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. -#### Zod schema methods - -All [Zod schema methods](https://zod.dev/?id=schema-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 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: @@ -790,7 +847,7 @@ These references will be transformed into objects containing a `collection` key ### 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. +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. 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](#generating-routes-from-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. @@ -995,9 +1052,9 @@ const { entry: product } = await getLiveEntry('products', Astro.params.slug); ### 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, using the same method as build-time collections. If the loader does not return a `rendered` property for an entry, the `` component will render nothing. +If your loader [returns a `rendered` property](#providing-rendered-content), 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](#error-handling-in-loaders), for example, to rewrite to a 404 page when content cannot be displayed: +You also have access to any [error returned by the live loader](#error-handling-in-live-loaders), for example, to rewrite to a 404 page when content cannot be displayed: ```astro "render(entry)" "" --- From 1b192b17803a172a705671593ab14ce271a379b1 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Wed, 22 Oct 2025 11:29:24 +0000 Subject: [PATCH 11/41] some polish to generating routes section --- src/content/docs/en/guides/content-collections.mdx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index 1e6c990636c70..1d255c36db3d4 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -1109,7 +1109,7 @@ if (error) { ## 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. @@ -1117,7 +1117,7 @@ The exact method for generating routes will depend on whether your pages are pre ### 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/[slug]`) 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). @@ -1146,9 +1146,9 @@ This will generate a page route for every entry in the `blog` collection. For ex 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. ::: -### Building for server output (SSR) +### Building routes on demand at request time -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). +If you have an adapter installed and are generating your routes at request time, you will not 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) for build-time collection pages that are generated once, upon first request, or [`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" @@ -1176,7 +1176,6 @@ const { Content } = await render(post); 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! ::: - ### Live collection limitations Live content collections have some limitations compared to build-time collections: @@ -1195,4 +1194,4 @@ Live collections use a different API than build-time content collections. Key di 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` +6. **User-facing functions**: Use `getLiveCollection`/`getLiveEntry` instead of `getCollection`/`getEntry` \ No newline at end of file From 7167df0ecbbbebd3b65a3e8dd85399fe8e1e2d51 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Wed, 22 Oct 2025 11:45:38 +0000 Subject: [PATCH 12/41] talk about generating pages for each type of collection to get links available earlier --- src/content/docs/en/guides/content-collections.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index 1d255c36db3d4..aa1ad43ef26f5 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -111,6 +111,8 @@ export const collections = { blog }; 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. thosands, or tens of thousands) and want to delay building a static page until it is needed. + :::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 Markdown or MDX blog posts. ::: @@ -154,6 +156,8 @@ 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](#build-time-content-collections) do. This is useful when accessing live, up-to-the-moment data is more important than achieving the performance of having your content available in a performant data storage layer that persists between site builds. + ## 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`: From d8be8e7eb11ee27c3f2e374d23b2fe2f8ec26b53 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Wed, 22 Oct 2025 12:00:36 +0000 Subject: [PATCH 13/41] placeholder content for astro:content reference items (and so links work) --- .../en/reference/modules/astro-content.mdx | 118 +++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/src/content/docs/en/reference/modules/astro-content.mdx b/src/content/docs/en/reference/modules/astro-content.mdx index cc72bd2d2a523..6b72a328fc3d7 100644 --- a/src/content/docs/en/reference/modules/astro-content.mdx +++ b/src/content/docs/en/reference/modules/astro-content.mdx @@ -12,7 +12,13 @@ import ReadMore from '~/components/ReadMore.astro';

-Content collections offer APIs to configure and query your Markdown or MDX documents in `src/content/`. For features and usage examples, [see our content collections guide](/en/guides/content-collections/). +Build-time content collections offer APIs to configure, query, and render your local Markdown, MDX, Markdoc, YAML, TOML, or JSON files as well as remote content. + +

+ +Live content collections offer APIs to configure, query and render fresh, up-to-the-moment live data from remote sources. + +For features and usage examples, [see our content collections guide](/en/guides/content-collections/). ## Imports from `astro:content` @@ -20,8 +26,11 @@ Content collections offer APIs to configure and query your Markdown or MDX docum import { z, defineCollection, + defineLiveCollection, getCollection, + getLiveCollection, getEntry, + getLiveEntry, getEntries, reference, render @@ -80,6 +89,58 @@ A `loader` is either an object or a function that allows you to load data from a [See the `Content Collection` guide](/en/guides/content-collections/#defining-the-collection-schema) for example usage. +### `defineLiveCollection()` + +

+ +**Type:** `(input: CollectionConfig) => CollectionConfig` + +

+ +`defineLiveCollection()` is a utility to configure a live collection in a `src/live.config.*` file. + +```ts title="src/content.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', + }), +}); + +// Expose your defined collection to Astro +// with the `collections` export +export const collections = { products }; +``` + +This function accepts the following properties: + +#### `loader` + +

+ +**Type:** () => Promise<Array<\{ id: string, [key: string]: any }> | Record<string, Record<string, any>>> | Loader + +

+ +A `loader` is either an object or a function that allows you to load data from any source, local or remote, into a live content collections. + +[See the `Content Collection` guide](/en/guides/content-collections/#creating-a-live-loader) for example usage. + +#### `schema` + +

+ +**Type:** ZodType | (context: SchemaContext) => ZodType + +

+ +`schema` is an optional Zod object to configure the type and shape of document frontmatter for a live collection. Each value must use [a Zod validator](https://github.com/colinhacks/zod). + +[See the `Content Collection` guide](/en/guides/content-collections/#using-zod-schemas-with-live-collections) for example usage. + ### `reference()`

@@ -151,6 +212,34 @@ const draftBlogPosts = await getCollection('blog', ({ data }) => { [See the `Content Collection` guide](/en/guides/content-collections/#querying-collections) for example usage. +### `getLiveCollection()` + +

+ +**Type:** `(collection: string, filter?: (entry: CollectionEntry) => boolean) => CollectionEntry[]` + +

+ +`getLiveCollection()` is a function that retrieves a list of live content collection entries by collection name. + +It returns all items in the collection by default, and accepts an optional `filter` function to narrow by entry properties. This allows you to query for only some items in a collection based on `id` or frontmatter values via the `data` object. + +```astro +--- +import { getLiveCollection } from 'astro:content'; + +// Get all `src/content/blog/` entries +const allBlogPosts = await getLiveCollection('blog'); + +// Only return posts with `draft: true` in the frontmatter +const draftBlogPosts = await getLiveCollection('blog', ({ data }) => { + return data.draft === true; +}); +--- +``` + +[See the `Content Collection` guide](/en/guides/content-collections/#accessing-live-data) for example usage. + ### `getEntry()`

@@ -180,6 +269,33 @@ const enterpriseCaptainProfile = await getEntry(enterprisePost.data.captain); See the `Content Collections` guide for examples of [querying collection entries](/en/guides/content-collections/#querying-collections). +### `getLiveEntry()` + +

+ +**Types:** +* `(collection: string, id: string) => Promise | undefined>` +* `({ collection: string, id: string }) => Promise | undefined>` + +

+ +`getLiveEntry()` is a function that retrieves a single live collection entry by collection name and the entry `id`. `getLiveEntry()` can also be used to get referenced entries to access the `data` or `body` properties: + +```astro +--- +import { getLiveEntry } from 'astro:content'; + +const enterprisePost = await getLiveEntry('blog', 'enterprise'); + +const picardProfile = await getLiveEntry('captains', 'picard'); + +// Get the profile referenced by `data.captain` +const enterpriseCaptainProfile = await getLiveEntry(enterprisePost.data.captain); +--- +``` + +See the `Content Collections` guide for examples of [querying collection entries](/en/guides/content-collections/#accessing-live-data). + ### `getEntries()`

From 53d6f32ba7c606af0999933e6cb03d996396b6c7 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Wed, 22 Oct 2025 13:14:38 +0000 Subject: [PATCH 14/41] update `/en/` broken links --- src/content/docs/en/guides/cms/keystatic.mdx | 2 +- src/content/docs/en/guides/content-collections.mdx | 6 +++--- src/content/docs/en/guides/imports.mdx | 2 +- src/content/docs/en/guides/integrations-guide/markdoc.mdx | 2 +- src/content/docs/en/guides/integrations-guide/mdx.mdx | 4 ++-- src/content/docs/en/guides/media/cloudinary.mdx | 2 +- .../en/guides/migrate-to-astro/from-create-react-app.mdx | 2 +- .../docs/en/guides/migrate-to-astro/from-gatsby.mdx | 2 +- .../docs/en/guides/migrate-to-astro/from-nextjs.mdx | 2 +- src/content/docs/en/guides/upgrade-to/v6.mdx | 2 +- src/content/docs/en/reference/cli-reference.mdx | 2 +- .../docs/en/reference/content-loader-reference.mdx | 4 ++-- .../errors/content-collection-missing-loader.mdx | 2 +- .../docs/en/reference/errors/file-glob-not-supported.mdx | 2 +- .../en/reference/errors/legacy-content-config-error.mdx | 2 +- src/content/docs/en/reference/modules/astro-content.mdx | 8 ++++---- src/content/docs/en/tutorial/6-islands/4.mdx | 2 +- 17 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/content/docs/en/guides/cms/keystatic.mdx b/src/content/docs/en/guides/cms/keystatic.mdx index 6d26abd9d3ff6..73a116d768d4e 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/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index aa1ad43ef26f5..b0500ca9fbfb2 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -135,7 +135,7 @@ Each individual collection configures: - a `loader` for your data source, and optionally for type safety (required) - a `schema` 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. +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 your live loaders](#type-safety-in-live-loaders). 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. @@ -406,7 +406,7 @@ You can then [render both content and metadata from live collection entries](#re ### Error handling in live 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. +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](#creating-live-loader-error-types) for proper typing. Astro will generate some errors itself, depending on the response from the loader: @@ -944,7 +944,7 @@ const { Content, headings } = await render(entry); ``` -When working with MDX entries, you can also [pass your own components to ``](/en/guides/integrations-guide/mdx/#passing-components-to-mdx-content) to replace HTML elements with custom alternatives. +When working with MDX entries, you can also [pass your own components to ``](/en/guides/integrations-guide/mdx/) to replace HTML elements with custom alternatives. ### Passing content as props diff --git a/src/content/docs/en/guides/imports.mdx b/src/content/docs/en/guides/imports.mdx index 5651cb5272e72..6a7177bb0fc1b 100644 --- a/src/content/docs/en/guides/imports.mdx +++ b/src/content/docs/en/guides/imports.mdx @@ -352,7 +352,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/markdoc.mdx b/src/content/docs/en/guides/integrations-guide/markdoc.mdx index edd27c10e453f..69bd40b76f607 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 cf984dc08dc86..be61ff5eb32ae 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, z } from 'astro:content'; diff --git a/src/content/docs/en/guides/media/cloudinary.mdx b/src/content/docs/en/guides/media/cloudinary.mdx index c2df8e3c20686..32e577517bed5 100644 --- a/src/content/docs/en/guides/media/cloudinary.mdx +++ b/src/content/docs/en/guides/media/cloudinary.mdx @@ -134,7 +134,7 @@ export const collections = { } ``` -You can then use the [`getCollection()` or `getEntry()` query functions](/en/guides/content-collections/#querying-collections) to select one or many images or videos from your collection. +You can then use the [`getCollection()` or `getEntry()` query functions](/en/guides/content-collections/#querying-build-time-collections) to select one or many images or videos from your collection. See [Cloudinary's `cldAssetsLoader` documentation](https://astro.cloudinary.dev/cldassetsloader/basic-usage) for more information. diff --git a/src/content/docs/en/guides/migrate-to-astro/from-create-react-app.mdx b/src/content/docs/en/guides/migrate-to-astro/from-create-react-app.mdx index 5ba0f8a20afed..4c1be6b53e1bf 100644 --- a/src/content/docs/en/guides/migrate-to-astro/from-create-react-app.mdx +++ b/src/content/docs/en/guides/migrate-to-astro/from-create-react-app.mdx @@ -349,7 +349,7 @@ const randomUser = data.results[0]; --- ``` -See more about local files imports with [`import.meta.glob()`](/en/guides/imports/#importmetaglob), [querying using the Collections API](/en/guides/content-collections/#querying-collections) or [fetching remote data](/en/guides/data-fetching/). +See more about local files imports with [`import.meta.glob()`](/en/guides/imports/#importmetaglob), [querying with content collections](/en/guides/content-collections/#querying-build-time-collections) or [fetching remote data](/en/guides/data-fetching/). ### CRA Styling to Astro diff --git a/src/content/docs/en/guides/migrate-to-astro/from-gatsby.mdx b/src/content/docs/en/guides/migrate-to-astro/from-gatsby.mdx index 0a35bf13c2977..34fe9b2d54a86 100644 --- a/src/content/docs/en/guides/migrate-to-astro/from-gatsby.mdx +++ b/src/content/docs/en/guides/migrate-to-astro/from-gatsby.mdx @@ -36,7 +36,7 @@ When you rebuild your Gatsby site in Astro, you will notice some important diffe - [Astro components](/en/basics/astro-components/) are not written as exported functions that return page templating. Instead, you'll split your code into a "code fence" for your JavaScript and a body exclusively for the HTML you generate. -- [Local file data](/en/guides/imports/): Gatsby uses GraphQL to retrieve data from your project files. Astro uses ESM imports and top-level await functions (e.g. [`import.meta.glob()`](/en/guides/imports/#importmetaglob), [`getCollection()`](/en/guides/content-collections/#querying-collections)) to import data from your project files. You can manually add GraphQL to your Astro project but it is not included by default. +- [Local file data](/en/guides/imports/): Gatsby uses GraphQL to retrieve data from your project files. Astro uses ESM imports and top-level await functions (e.g. [`import.meta.glob()`](/en/guides/imports/#importmetaglob), [`getCollection()`](/en/guides/content-collections/#querying-build-time-collections)) to import data from your project files. You can manually add GraphQL to your Astro project but it is not included by default. ## Convert your Gatsby Project diff --git a/src/content/docs/en/guides/migrate-to-astro/from-nextjs.mdx b/src/content/docs/en/guides/migrate-to-astro/from-nextjs.mdx index e997018bbaed2..4839134dd5546 100644 --- a/src/content/docs/en/guides/migrate-to-astro/from-nextjs.mdx +++ b/src/content/docs/en/guides/migrate-to-astro/from-nextjs.mdx @@ -405,7 +405,7 @@ const randomUser = data.results[0]; --- ``` -See more about local files imports with [`import.meta.glob()`](/en/guides/imports/#importmetaglob), [querying using the Collections API](/en/guides/content-collections/#querying-collections) or [fetching remote data](/en/guides/data-fetching/). +See more about local files imports with [`import.meta.glob()`](/en/guides/imports/#importmetaglob), [querying with content collections](/en/guides/content-collections/#querying-build-time-collections) or [fetching remote data](/en/guides/data-fetching/). ### Next Styling to Astro diff --git a/src/content/docs/en/guides/upgrade-to/v6.mdx b/src/content/docs/en/guides/upgrade-to/v6.mdx index bac4071d5915f..4df5f824f5db1 100644 --- a/src/content/docs/en/guides/upgrade-to/v6.mdx +++ b/src/content/docs/en/guides/upgrade-to/v6.mdx @@ -205,7 +205,7 @@ 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/#built-in-loaders) and define the `pattern` and `base` for your collection entries: +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={3,6} // src/content.config.ts diff --git a/src/content/docs/en/reference/cli-reference.mdx b/src/content/docs/en/reference/cli-reference.mdx index 77f353b74f5e6..0869b7535537c 100644 --- a/src/content/docs/en/reference/cli-reference.mdx +++ b/src/content/docs/en/reference/cli-reference.mdx @@ -399,7 +399,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/content-loader-reference.mdx b/src/content/docs/en/reference/content-loader-reference.mdx index 14a119663d97b..f9b934faa653f 100644 --- a/src/content/docs/en/reference/content-loader-reference.mdx +++ b/src/content/docs/en/reference/content-loader-reference.mdx @@ -10,9 +10,9 @@ Astro's Content Loader API allows you to load your data from any source, local ## What is a loader? -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. +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/#build-time-collection-loaders) are used to load content from the file system, and you can create your own loaders to load content from other sources. -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. +Each collection needs a loader defined in its schema. 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. ## Built-in loaders 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 index 224406aa602c6..13652a54399f6 100644 --- a/src/content/docs/en/reference/errors/content-collection-missing-loader.mdx +++ b/src/content/docs/en/reference/errors/content-collection-missing-loader.mdx @@ -21,4 +21,4 @@ import DontEditWarning from '~/components/DontEditWarning.astro' A content collection is missing a loader definition. Make sure that each collection in your content config file has a loader. **See Also:** -- [Content collections configuration](/en/guides/content-collections/#defining-the-collection-loader) +- [Content collections configuration](/en/guides/content-collections/) 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..be9f4ce3a5767 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/guides/content-collections/#the-file-loader) 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 index 8dcd318ea0da5..4da8ce6546963 100644 --- a/src/content/docs/en/reference/errors/legacy-content-config-error.mdx +++ b/src/content/docs/en/reference/errors/legacy-content-config-error.mdx @@ -23,4 +23,4 @@ A legacy content config file was found. Move the file to `src/content.config.ts` See the [Astro 6 migration guide](/en/guides/upgrade-to/v6/#removed-legacy-content-collections) for more information. **See Also:** -- [Content collections configuration](/en/guides/content-collections/#the-collection-config-file) +- [Content collections configuration](/en/guides/content-collections/#build-time-content-collections) diff --git a/src/content/docs/en/reference/modules/astro-content.mdx b/src/content/docs/en/reference/modules/astro-content.mdx index 6b72a328fc3d7..0e0bfdee8dbfd 100644 --- a/src/content/docs/en/reference/modules/astro-content.mdx +++ b/src/content/docs/en/reference/modules/astro-content.mdx @@ -70,12 +70,12 @@ This function accepts the following properties:

**Type:** () => Promise<Array<\{ id: string, [key: string]: any }> | Record<string, Record<string, any>>> | Loader - +

A `loader` is either an object or a function that allows you to load data from any source, local or remote, into content collections. -[See the `Content Collection` guide](/en/guides/content-collections/#defining-the-collection-loader) for example usage. +[See the `Content Collection` guide](/en/guides/content-collections/#build-time-collection-loaders) for example usage. #### `schema` @@ -210,7 +210,7 @@ const draftBlogPosts = await getCollection('blog', ({ data }) => { --- ``` -[See the `Content Collection` guide](/en/guides/content-collections/#querying-collections) for example usage. +[See the `Content Collection` guide](/en/guides/content-collections/#querying-build-time-collections) for example usage. ### `getLiveCollection()` @@ -267,7 +267,7 @@ const enterpriseCaptainProfile = await getEntry(enterprisePost.data.captain); --- ``` -See the `Content Collections` guide for examples of [querying collection entries](/en/guides/content-collections/#querying-collections). +See the `Content Collections` guide for examples of [querying collection entries](/en/guides/content-collections/#querying-build-time-collections). ### `getLiveEntry()` diff --git a/src/content/docs/en/tutorial/6-islands/4.mdx b/src/content/docs/en/tutorial/6-islands/4.mdx index 06ad6a55abe89..066162404180c 100644 --- a/src/content/docs/en/tutorial/6-islands/4.mdx +++ b/src/content/docs/en/tutorial/6-islands/4.mdx @@ -147,7 +147,7 @@ Upgrade to the latest version of Astro, and upgrade all integrations to their la 1. Create a page file called `src/pages/posts/[...slug].astro`. Your Markdown and MDX files no longer automatically become pages using Astro's file-based routing when they are inside a collection, so you must create a page responsible for generating each individual blog post. -2. Add the following code to [query your collection](/en/guides/content-collections/#querying-collections) to make each blog post's slug and page content available to each page it will generate: +2. Add the following code to [query your collection](/en/guides/content-collections/#querying-build-time-collections) to make each blog post's slug and page content available to each page it will generate: ```astro title="src/pages/posts/[...slug].astro" --- From 8fb34fd0ea1b7299c2e72c74c39658762b427319 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Wed, 22 Oct 2025 13:30:25 +0000 Subject: [PATCH 15/41] fix one more en link --- src/content/docs/en/guides/upgrade-to/v6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/en/guides/upgrade-to/v6.mdx b/src/content/docs/en/guides/upgrade-to/v6.mdx index 4df5f824f5db1..c1d5076bf8241 100644 --- a/src/content/docs/en/guides/upgrade-to/v6.mdx +++ b/src/content/docs/en/guides/upgrade-to/v6.mdx @@ -194,7 +194,7 @@ If you have [content collections errors](/en/reference/error-reference/#content-
no content collections configuration file -Create `src/content.config.ts` and [define your collections](/en/guides/content-collections/#defining-collections) in it. +Create `src/content.config.ts` and [define your collections](/en/guides/content-collections/#build-time-collections) in it.
From 2738a82fa351df6d56e29997905c30516f667011 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Wed, 22 Oct 2025 13:46:18 +0000 Subject: [PATCH 16/41] actcually fix en link --- src/content/docs/en/guides/upgrade-to/v6.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/en/guides/upgrade-to/v6.mdx b/src/content/docs/en/guides/upgrade-to/v6.mdx index c1d5076bf8241..31b8b1c034abc 100644 --- a/src/content/docs/en/guides/upgrade-to/v6.mdx +++ b/src/content/docs/en/guides/upgrade-to/v6.mdx @@ -194,7 +194,7 @@ If you have [content collections errors](/en/reference/error-reference/#content-
no content collections configuration file -Create `src/content.config.ts` and [define your collections](/en/guides/content-collections/#build-time-collections) in it. +Create `src/content.config.ts` and [define your collections](/en/guides/content-collections/#build-time-content-collections) in it.
From f4e8d2a2eca44ba66e501ddacb5c1c97260763b1 Mon Sep 17 00:00:00 2001 From: sarahrainsberger Date: Wed, 22 Oct 2025 14:14:40 +0000 Subject: [PATCH 17/41] fix international links, mostly by deleting German pages slated for deletion anyway --- .../from-create-react-app.mdx | 368 ------- .../docs/de/reference/api-reference.mdx | 940 ------------------ src/content/docs/it/tutorial/6-islands/4.mdx | 2 +- 3 files changed, 1 insertion(+), 1309 deletions(-) delete mode 100644 src/content/docs/de/guides/migrate-to-astro/from-create-react-app.mdx delete mode 100644 src/content/docs/de/reference/api-reference.mdx diff --git a/src/content/docs/de/guides/migrate-to-astro/from-create-react-app.mdx b/src/content/docs/de/guides/migrate-to-astro/from-create-react-app.mdx deleted file mode 100644 index bea81ed884c76..0000000000000 --- a/src/content/docs/de/guides/migrate-to-astro/from-create-react-app.mdx +++ /dev/null @@ -1,368 +0,0 @@ ---- -title: Migrieren von Create React App (CRA) -description: Tipps zum Migrieren eines existierenden Create React App Projekts zu Astro -type: migration -stub: true -framework: Create React App -i18nReady: true ---- -import AstroJSXTabs from '~/components/tabs/AstroJSXTabs.astro'; -import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro'; -import { FileTree } from '@astrojs/starlight/components'; -import ReadMore from '~/components/ReadMore.astro'; -import Badge from "~/components/Badge.astro" - -Astros [React-Integration](/de/guides/integrations-guide/react/) ermöglicht dir, [React-Komponenten in Astro-Komponenten zu verwenden](/de/guides/framework-components/), auch komplette React-Projekte wie Create React App (CRA)! - -```astro title="src/pages/index.astro" ---- -// Importiere die App-Komponente deines Stammverzeichnisses -import App from '../cra-project/App.jsx'; ---- - - -``` - -Lies in [Build a Single Page Application (SPA) with Astro (englischer Blogpost)](https://logsnag.com/blog/react-spa-with-astro) , wie man React Router in Astro verwendet. - -Viele Apps werden als komplette React-Apps "einfach funktionieren", wenn du sie direkt in dein Astro-Projekt mit der React-Integration installierst. Das ist eine gute Möglichkeit, dein Projekt sofort zum Laufen zu bringen und deine App funktionsfähig zu halten, während du zu Astro migrierst. - -Mit der Zeit kannst du deine Struktur stückweise in eine Kombination aus `.astro`- und `.jsx`- Komponenten umbauen. Dabei wirst du merken, dass du weniger React-Komponenten brauchst als du vielleicht denkst! - -Hier sind ein paar grundlegende Konzepte und Migrations­strategien, die dir den Einstieg erleichtern. Nutze den Rest unserer Dokumente und unsere [Discord-Community](https://astro.build/chat), um weiterzumachen! - -## Wesentliche Gemeinsamkeiten zwischen CRA und Astro - -- Die [Syntax von `.astro`-Dateien ist ähnlich zu JSX](/de/reference/astro-syntax/#unterschiede-zwischen-astro-und-jsx). Astro zu schreiben sollte sich also gewohnt anfühlen. - -- Astro verwendet dateienbasierts Routing, und [erlaubt spezielle Dateinamen, um dynamische Routen zu erstellen](/de/guides/routing/#dynamische-routen). - -- Astro ist [komponenten-basiert](/de/basics/astro-components/), und deine Markupstruktur wird vor und nach der Migration ähnlich sein. - -- Astro hat [offizielle Integrationen für React, Preact und Solid](/de/guides/integrations-guide/react/), damit kannst du deine vorhandenen JSX-Komponenten verwenden. Beachte, dass in diese Dateien in Astro eine `.jsx`/`.tsx` oder `.astro` Endung haben **müssen**. - -- Astro unterstützt die [Installation von NPM-Paketen](/de/guides/imports/#npm-pakete), inklusive React-Bibliotheken. Viele deiner vorhandenen Abhängigkeiten werden auch in Astro funktionieren. - -## Wesentliche Unterschiede zwischen CRA und Astro - -Wenn du deine CRA-Webseite in Astro nachbilden willst, werden dir einige wichtige Unterschiede auffallen: - -- CRA ist eine Single Page Application (App mit einer einzigen Seite), welche eine `index.js`-Datei als das Stammverzeichnis deines Projekts verwendet. Astro ist eine Multiple Page Application (App mit mehreren Seiten), und `index.astro` ist deine Startseite. - -- [`.astro`-Komponenten](/de/basics/astro-components/) sind nicht als exportierte Funktionen geschrieben, die Seitenvorlagen zurückgeben. Stattdessen wirst du deinen Code in einen "Code-Zaun" mit deinem JavaScript-Code und einem Body, der ausschließlich deinen generierten HTML-Code enthält, aufteilen. - -- [Inhaltsorientiert](/de/concepts/why-astro/#inhaltsorientiert): Astro wurde als Auslage für deine Inhalte entwickelt und erlaubt dir, interaktive Elemente nur einzubauen, wenn du sie brauchst. Eine existierende CRA-App könnte für ausgiebige client-seitige Interaktivität ausgelegt sein und benötigt vielleicht fortgeschrittene Astro-Techniken, um komplexere Elemente wie Dashboards durch `.astro`-Komponenten zu ersetzen. - -## Füge deine CRA zu Astro hinzu - -Deine vorhandene App kann direkt in einem neuen Astro-Projekt gerendert werde, oftmals auch ohne Änderungen an deinem Code. - -### Erstelle ein neues Astro-Projekt - -Verwende den `create astro`-Befehl, um Astros CLI Wizard zu starten, und wähle ein neues "leeres" Astro-Projekt. - - - - ```shell - npm create astro@latest - ``` - - - ```shell - pnpm create astro@latest - ``` - - - ```shell - yarn create astro@latest - ``` - - - -### Füge Integrationen und Abhängigkeiten hinzu - -Füge die React-Integration mit dem `astro add`-Befehl hinzu. Wenn deine App Tailwind oder MDX verwendet, kannst du mehrere Astro-Integrationen mit einem Befehl hinzufügen: - - - - ```shell - npx astro add react - npx astro add react tailwind mdx - ``` - - - ```shell - pnpm astro add react - pnpm astro add react tailwind mdx - ``` - - - ```shell - yarn astro add react - yarn astro add react tailwind mdx - ``` - - - -Wenn deine CRA-App andere Abhängigkeiten (z.B. NPM-Pakete) benötigt, kannst du diese entweder individuell über die Kommandozeile installieren oder durch das Hinzufügen in die `package.json`-Datei deines Astro-Projekts, wenn du danach den Installationsbefehl laufen lässt. Beachte, dass viele, aber nicht alle, React-Abhängigkeiten auch in Astro funktionieren werden. - -### Füge deine vorhanden App-Dateien hinzu - -Kopiere deine vorhanden CRA-Projektdateien und Ordner (z.B. `components`, `hooks`, `styles` etc.) in einen neuen Ordner in `src/`, während du die Struktur aufrecht erhältst, damit deine App weiterhin funktioniert. Beachte, dass alle `.js`-Dateiendungen in `.jsx` oder `.tsx` umbenannt werden müssen. - -Füge keine Konfigurations­dateien hinzu. Du wirst Astros eigene `astro.config.mjs`, `package.json` und `tsconfig.json` bearbeiten können. - -Verschiebe den Inhalt des Ordners `public/` deiner App (z. B. statische Assets) in den Ordner `public/` von Astro. - - -- public/ - - logo.png - - favicon.ico - - ... -- src/ - - cra-project/ - - App.jsx - - ... - - pages/ - - index.astro -- astro.config.mjs -- package.json -- tsconfig.json - - -### Rendere deine App - -Importiere deine Stammverzeichnis-Komponenten in das Frontmatter von `index.astro` und rendere die ``-Komponente in deiner Seitenvorlage: - -```astro title="src/pages/index.astro" ---- -import App from '../cra-project/App.jsx'; ---- - -``` - -:::note[Client-Direktiven] -Deine App benötigt eine Client-Direktive für Interaktivität. Astro rendert deine React-App als statisches HTML, bis du zu client-seitigem JavaScript wechselst. - -Benutze `client:load`, um sicherzustellen, dass deine App sofort vom Server geladen wird, oder `client:only="react"`, um das serverseitige Rendering zu überspringen und deine App komplett clientseitig laufen zu lassen. -::: - -## Verwandle deine CRA in Astro - -Nachdem du [deine vorhandene App in Astro hinzugefügt hast](#füge-deine-cra-zu-astro-hinzu), willst du wahrscheinlich die App auch in Astro umwandeln! - -Du replizierst ein ähnliches komponenten­basiertes Design [unter Verwendung von Astro HTML-Vorlagenkomponenten für deine Grundstruktur](/de/basics/astro-components/), während du einzelne React-Komponenten (die selbst ganze Apps sein können!) für Inseln der Interaktivität importierst und einbindest. - -Jede Migration sieht anders aus und kann schrittweise durchgeführt werden, ohne dass die Funktionalität deiner App unterbrochen wird. Konvertiere deine Komponenten in deinem eigenen Tempo, sodass deine App mit der Zeit immer mehr von Astro-Komponenten angetrieben wird. - -Während du deine React-App konvertierst, entscheidest du, welche React-Komponenten du [als Astro-Komponenten umschreibst](#jsx-dateien-in-astro-dateien-umwandeln) und welche nicht. Deine einzige Einschränkung besteht darin, dass Astro-Komponenten zwar React-Komponenten importieren können, React-Komponenten jedoch nur andere React-Komponenten importieren dürfen: - -```astro title="src/pages/static-components.astro" ins={2,7} ---- -import MyReactComponent from '../components/MyReactComponent.jsx'; ---- - - -

Verwende React-Komponenten direkt in Astro!

- - - -``` - -Anstatt Astro-Komponenten in React-Komponenten zu importieren, kannst du mehrere React-Komponenten in einer einzelnen Astro-Komponente verschachteln: - -```astro title="src/pages/nested-components.astro" {2,3,5,8,10} ---- -import MyReactSidebar from '../components/MyReactSidebar.jsx'; -import MyReactButton from '../components/MyReactButton.jsx'; ---- - -

Hier ist eine Seitenleiste mit etwas Text und einem Button.

-
- -
-
-``` - -Vielleicht hilft es dir, zuerst über [Astro-Inseln](/de/concepts/islands/) und [Astro-Komponenten](/de/basics/astro-components/) zu lernen, bevor du dein CRA in ein Astro-Projekt umwandelst. - -### Vergleiche: JSX vs Astro - -Vergleiche folgende React-Komponente und die entsprechende Astro-Komponente: - - - - ```jsx title="StarCount.jsx" - import React, { useState, useEffect } from 'react'; -import Header from './Header'; -import Footer from './Footer'; - -const Component = () => { - const [stars, setStars] = useState(0); - const [message, setMessage] = useState(''); - - useEffect(() => { - const fetchData = async () => { - const res = await fetch('https://api.github.com/repos/withastro/astro'); - const json = await res.json(); - - setStars(json.stargazers_count || 0); - setMessage(json.message); - }; - - fetchData(); - }, []); - - return ( - <> -
-

Astro hat {stars} 🧑‍🚀

-