Astro 7.1

By
Emanuele Stoppa
Matthew Phillips

Astro 7.1 is here! This release is about giving you more control: run multiple dev servers side by side with a new --ignore-lock flag, and shape pagination URLs to match how you actually deploy your site with a format function on paginate(). It also adds new CSP directives for finer-grained script and style policies, an option to lower memory usage for large content collections, and an experimental way to chunk content storage.

Explore what’s new in this release:

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

Finer-grained CSP control for inline scripts and styles

Astro CSP now has built-in support for the following directives, giving you more control over your resources:

These resources are specialized versions of the script-src and style-src counterparts, and they will allow you to solve problems that you couldn’t before.

For example, you can now accept inline styles as unsafe, without giving up safety for external CSS file:

astro.config.mjs
import { defineConfig } from "astro/config"
export default defineConfig({
security: {
csp: {
styleDirective: [{
resource: "'unsafe-line'",
kind: "attribute"
}]
}
}
})

To learn more about the new configuration and APIs, refer to the runtime docs and the configuration docs.

Full control over pagination URLs

Pagination URLs generated by paginate() haven’t always matched how you actually deploy your site. For example, if you build static .html files (build: { format: 'file' }) and deploy to a host without URL-rewrite rules, the next/prev/first/last URLs it returned were clean paths like /blog/2, which don’t correspond to any file on disk.

You now have full control over these URLs with a new format function on paginate(). It receives each generated URL as a string and lets you transform it however you like, for example to append .html:

src/pages/pokemon.astro
---
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;
---

Run multiple dev servers at once

Sometimes you want a second dev server without giving up the one you already have running. For example, you’re debugging something and want to temporarily start another instance with verbose logging, while keeping your regular dev server (and its state) exactly as it is.

Astro 7 introduced a lockfile so that AI coding agents don’t accidentally spin up duplicate dev servers for the same project. As a side effect, running astro dev while another instance was already active would just error out, even when you started it yourself on purpose.

Astro 7.1 brings that workflow back with a new --ignore-lock flag that skips the lockfile check, so you can start as many dev servers as you like for the same project:

astro dev --ignore-lock

The instance started with --ignore-lock runs independently of the others, which means astro dev stop, astro dev status, and astro dev logs won’t know about it. It’s for cases like this one, where you just need a quick, throwaway second server, not another one you’ll manage long-term.

Lower memory usage for large content collections

The glob() loader renders your Markdown entries as soon as it syncs your content collection, and caches the rendered HTML so it doesn’t have to do that work again on the next build. For most sites, that’s a great trade: sync is a little more expensive, but rebuilds are fast.

That trade gets more expensive as a collection grows, or as rendering produces more output than its source Markdown. Caching all of that rendered HTML in memory during sync adds up.

You can now opt individual collections out of eager rendering with the deferRender option:

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 }),
});

With deferRender: true, entries are stored without being rendered during sync. Rendering happens later, on demand, when a page actually needs it, the same way .mdx files have always worked. You give up caching rendered HTML across builds, but for large, heavy collections that’s a worthwhile trade for lower memory usage during sync.

Logger improvements

Custom loggers can now be configured consistently with other APIs you might be using (e.g. fonts or sessions). Passing a URL allows you to override the configuration at runtime or use Vite’s built-in features:

astro.config.mjs
import { defineConfig } from "astro/config"
export default defineConfig({
logger: {
entrypoint: new URL("./src/custom-logger.js", import.meta.url)
}
})

Additionally, you can use AstroRuntimeLogger. This is a useful type you can use in those files that use the runtime Astro logger:

src/utils/requestHandler.ts
import type { AstroRuntimeLogger } from "astro";
export function handleRequest(req: Request, astroLogger: AstroRuntimeLogger) {
astroLogger.info("Incoming request");
}

Experimental content storage

Historically, content collections save their data into one single, deserialized file called .astro/data-store.json. However, for users who have big content collections, this could be a problem because there are some platforms that impose restrictions on the size of files.

Astro now has an experimental flag called experimental.collectionStorage that allows you to chunk the data into multiple files:

astro.config.mjs
import { defineConfig } from "astro/config"
export default defineConfig({
experimental: {
collectionStorage: "chunked"
}
})

When "chunked" is selected, Astro splits the content collection data every 10Mb.

Community

The Astro core team is:

Alexander Niebuhr, Armand Philippot, Chris Swithinbank, Emanuele Stoppa, Erika, Florian Lefebvre, Fred Schott, HiDeoo, Luiz Ferraz, Matt Kane, Matthew Phillips, Reuben Tier, Sarah Rainsberger, and Yan Thomas.

Special thanks to everyone who contributed to Astro 7.1 with code, docs, reviews, and testing, including:

Adam Chalemian, Alberto Schiabel, Alexander Kireyev, Andreas Deininger, Ari4ka, artboy, Bugo, caixetad-cyber, cevdet, Coding in Public, Cristhian F, Cristofer Hippleheuser, David Dal Busco, deniz, Ethan Hawksley, Felix Schneider, Felmon, fkatsuhiro, Franco Kaddour, Jan Kubica, Junseong Park, Keisuke Hayashi, knj, ld-web, Louis Escher, LRubin, marcos-corrochano, Martin Trapp, Nico D., ocavue, Prayaksh Upadhyay, randomguy-2650, Roman, Ronit Sonawane, royy92, Shinya Fujino, Simon, Thomas Bonnet, tombennet, uniboxx, Vladyslav Shevchenko, WavyCat, and

We hope you enjoy Astro 7.1. If you run into issues or want to share feedback, please join us on Discord, post on GitHub, or reach out on Bluesky, Twitter, and Mastodon.