Astro 4.14

By
Erika
Matt Kane

Astro 4.14 is out now! This release includes the first experimental release of the Content Layer API, our new super-flexible solution for managing content in Astro projects, support for Intellisense inside content files, and more.

This release includes the following highlights:

To upgrade an existing project, use the automated @astrojs/upgrade CLI tool. Alternatively, upgrade manually by running the upgrade command for your package manager:

# Recommended:
npx @astrojs/upgrade
# Manual:
npm install astro@latest
pnpm upgrade astro --latest
yarn upgrade astro --latest

Experimental: Content Layer API

In Astro 2.0 we introduced Content Collections, a powerful way to manage local content in Astro projects. While this has helped hundreds of thousands of developers build content-driven sites with Astro, we’ve heard your feedback that you want more flexibility and power in managing your content. We’re excited to announce the experimental release of the next generation of content collections in Astro: the Content Layer API.

The new Content Layer API builds upon content collections, taking them beyond local files in src/content/ and allowing you to fetch content from anywhere, including remote APIs. These new collections work alongside your existing content collections, and you can migrate them to the new API at your own pace. We think you’ll want to soon, because they have lots of advantages, but there’s no rush – the existing collections will continue to work as they always have.

Performance

The Content Layer API is the first step in scaling Astro to support fast builds for sites with tens or hundreds of thousands of pages. The new API is designed to be more efficient and performant in the way it loads content. It caches content locally to avoid the need to keep hitting APIs and has dramatically improved handling of local Markdown and MDX files. This benchmark shows the performance when building a site with 10,000 pages on a Macbook Air M1:

Astro 4.13Astro 4.14 (Content Layer)
MarkdownBuild Time136.29s25.96s5.3x faster
Memory763.50MB276.22MB64% less
MDXBuild Time129.82s66.70s1.9x faster
Memory897.91MB674.39MB25% less

We plan to continue improving the performance of the Content Layer API in future releases, including adding support for a SQLite backend to handle even larger sites.

Getting started

To try out the new Content Layer API, enable it in your Astro config:

import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
contentLayer: true
}
})

You can then create collections in your src/content/config.ts using the Content Layer API.

Loading your content

The core of the new Content Layer API is the loader, a function that fetches content from a source and caches it in a local data store. Astro 4.14 ships with built-in glob() and file() loaders to handle your local Markdown, MDX, Markdoc, and JSON files:

// src/content/config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
// The ID is a slug generated from the path of the file relative to `base`
loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
schema: z.object({
title: z.string(),
description: z.string(),
publishDate: z.coerce.date(),
})
});
export const collections = { blog };

You can then use the content in your site:

---
import { getEntry, render } from 'astro:content';
const post = await getEntry('blog', Astro.params.slug);
const { Content } = await render(entry);
---
<Content />

Creating a loader

You’re not restricted to the built-in loaders – we hope you’ll try building your own. You can fetch content from anywhere and return an array of entries:

// src/content/config.ts
const countries = defineCollection({
loader: async () => {
const response = await fetch("https://restcountries.com/v3.1/all");
const data = await response.json();
// Must return an array of entries with an id property,
// or an object with IDs as keys and entries as values
return data.map((country) => ({
id: country.cca3,
...country,
}));
},
// optionally add a schema to validate the data and make it type-safe for users
// schema: z.object...
});
export const collections = { countries };

For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading while also giving full access to the data store. It also allows a loader to define its own schema, including generating it dynamically based on the source API. See the the Content Layer API RFC for more details.

Sharing your loaders

Loaders are better when they’re shared! You can create a module that exports a loader and publish it to npm, and then anyone can use it on their site. Tag your packages with the keyword astro-loader so they can be found. We’re excited to see what the community comes up with! To get started, take a look at some examples. Here’s how to load content using an RSS/Atom feed loader:

// src/content/config.ts
import { defineCollection } from "astro:content";
import { feedLoader } from "@ascorbic/feed-loader";
const podcasts = defineCollection({
loader: feedLoader({
url: "https://feeds.99percentinvisible.org/99percentinvisible",
}),
});
export const collections = { podcasts };

Learn more

To find out more about using the Content Layer API, check out the Content Layer RFC and share your feedback.

Experimental: Intellisense inside content files

Astro 4.14 introduces experimental support for Intellisense inside the frontmatter of your content. This feature helps you write content files more efficiently by providing completions, validation, hover information, and more for frontmatter keys and values. These tools are based on your content schemas, and available directly in your editor.

This feature is available in VS Code and other editors that support the Language Server Protocol for Markdown, MDX, and Markdoc files.

To enable content file intellisense, add the following to your Astro config:

import { defineConfig } from 'astro';
export default defineConfig({
experimental: {
contentIntellisense: true
}
})

and in VS Code, enable the astro.content-intellisense setting. For other editors, pass contentIntellisense: true to the initialization parameters of the Astro language server.

{
"astro.content-intellisense": true
}

This feature currently only works in the editor and will be enabled in astro check in a future release.

Deprecate support for dynamic prerender values

In order to improve our bundling and tree-shaking capabilities, Astro 4.14 deprecates support for using dynamic values for the prerender option in your Astro pages.

This feature can now be replaced with the new astro:route:setup hook in Astro integrations, which allows you to dynamically control the prerendering of specific pages.

---
export const prerender = import.meta.env.PROD;
---
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
integrations: [setPrerender()],
});
function setPrerender() {
return {
name: 'set-prerender',
hooks: {
'astro:route:setup': ({ route }) => {
if (route.component.endsWith('/blog/[slug].astro')) {
route.prerender = true;
}
},
},
};
}

New injectTypes integration API

Type generation has become all the rage in recent years, and Astro is no exception! We use type generation pretty extensively for features like Astro DB and Content Collections (or the new Content Layer API).

Thanks to @florian-lefebvre, Astro integrations can now join the fun with the new injectTypes integration API! This API allows integrations to inject types into the user’s project, making it easier to provide type definitions for your integration’s features.

// my-integration/index.js
export default {
name: 'my-integration',
'astro:config:done': ({ injectTypes }) => {
injectTypes({
filename: "types.d.ts",
content: "declare module 'virtual:my-integration' {}"
})
}
};

For more information on this feature, check out the Astro integration API documentation.

Support for metastrings in the Code component

Astro 4.14 adds support for the meta attribute in the Code component. This attribute simulates using properties on code blocks in Markdown, for example ```js astro=cool, which can then be used by Shiki transformers to apply custom transformations to the code block.

---
import { Code } from "astro:components";
import { transformerMetaHighlight } from '@shikijs/transformers';
---
<Code
code={code}
lang="js"
transformers={[transformerMetaHighlight()]}
meta="{1,3}" />

Thanks to @jcayzac for this contribution!

Bug Fixes and Special Thanks

As we do, Astro 4.14 includes more bug fixes and smaller improvements that couldn’t make it into this post! Check out the full release notes to learn more.

Thanks to Sarah Rainsberger (@sarah11918), Yan (@yanthomasdev), Bjorn Lu (@bluwy) and everyone else who contributed to this release.