#17302 5f4dc03 Thanks @astrobot-houston! - Adds a new deferRender option to the glob() content loader
When set to true, renderable entries (such as Markdown) are not rendered during content sync. Instead, rendering is deferred until the entry is actually rendered in a page, using the same on-demand path that .mdx files already use.
This reduces memory usage during astro build for large collections whose rendered output is much larger than the source β for example, Markdown that uses heavy rehype plugins like rehype-katex. Such builds could previously run out of memory while storing the eagerly-rendered HTML for every entry.
// src/content.config.ts
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
const docs = defineCollection({
loader: glob({ pattern: '**/*.md', base: 'src/content/docs', deferRender: true }),
});
By default deferRender is false, preserving the existing behavior of rendering entries eagerly during sync so their rendered HTML can be cached across builds.
#17296 30698a2 Thanks @ematipico! - Adds a new experimental collectionStorage option for controlling how the content layer persists its data store
By default, Astro serializes the entire content layer data store to a single file (.astro/data-store.json). For very large content collections, this file can grow large enough to hit platform file-size limits.
Set experimental.collectionStorage: 'chunked' to instead split the data store across many smaller, content-addressed files inside a .astro/data-store/ directory, described by a manifest:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
collectionStorage: 'chunked',
},
});
Because each part file is named by a hash of its contents, unchanged parts keep the same name across builds and are not rewritten, and identical parts are deduplicated. The default value is 'single-file', which preserves the current behavior.
#17214 44c4989 Thanks @ematipico! - Adds support for the more specific CSP directives script-src-elem, script-src-attr, style-src-elem, and style-src-attr through a new kind option.
Previously, CSP was only scoped to generic script-src/style-src directives. Now each source or hash can be scoped to a narrower directive β for example, to allow inline style attributes (such as those from define:vars or Shiki) without loosening the policy for your <style> and <link> elements.
Scoping sources and hashes in your config
Each entry in resources and hashes can be an object with a kind property. Depending on whether you use scriptDirective or styleDirective, "element" targets script-src-elem or style-src-elem, "attribute" targets script-src-attr or style-src-attr, and "default" (the same as a bare string or hash) targets script-src or style-src.
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
security: {
csp: {
scriptDirective: {
resources: [{ resource: 'https://cdn.example.com', kind: 'element' }],
},
styleDirective: {
resources: [{ resource: "'unsafe-inline'", kind: 'attribute' }],
},
},
},
});
Scoping at runtime
The same kind option is available on the runtime CSP API, where the existing methods now also accept an object:
ctx.csp.insertScriptResource({ resource: 'https://cdn.example.com', kind: 'element' });
ctx.csp.insertStyleResource({ resource: "'unsafe-inline'", kind: 'attribute' });
#17258 84814d4 Thanks @astrobot-houston! - Adds a new format() option to the paginate utility. The format() option is a function that accepts the current URL of the page, and returns a new URL.
For example, when your host only supports URLs using the .html extension, you can use format() to add it to the generated URLs:
---
export async function getStaticPaths({ paginate }) {
// Load your data with fetch(), getCollection(), etc.
const response = await fetch(`https://pokeapi.co/api/v2/pokemon?limit=150`);
const result = await response.json();
const allPokemon = result.results;
// Return a paginated collection of paths for all items
return paginate(allPokemon, {
pageSize: 10,
format: (url) => `${url}.html`,
});
}
const { page } = Astro.props;
---
#17331 7db6420 Thanks @matthewp! - Adds a --ignore-lock flag to astro dev for starting a dev server without checking or writing the lock file, so it can run alongside an already-running dev server for the same project.
The new instance is not tracked by astro dev stop, astro dev status, or astro dev logs. --ignore-lock cannot be combined with --background (or an auto-detected AI agent environment, which runs dev servers in the background automatically) or --force, since those rely on the lock file.
astro dev --ignore-lock
#17389 16de021 Thanks @florian-lefebvre! - Allows passing URL entrypoints when configuring the logger
Matching other APIs like session drivers or font providers, the logger entrypoint can now be a URL:
import { defineConfig } from 'astro/config';
export default defineConfig({
logger: {
entrypoint: new URL('./logger.js', import.meta.url),
},
});