#14169f4e8889 Thanks @ascorbic! - Skips trailing slash handling for paths that start with /..
#1417034e6b3a Thanks @ematipico! - Fixes an issue where static redirects couldn’t correctly generate a redirect when the destination is a prerendered route, and the output is set to "server".
#14169f4e8889 Thanks @ascorbic! - Fixes a bug that prevented images from being displayed in dev when using the Netlify adapter with trailingSlash set to always
#1405919f53eb Thanks @benosmac! - Fixes a bug in i18n implementation, where Astro didn’t emit the correct pages when fallback is enabled, and a locale uses a catch-all route, e.g. src/pages/es/[...catchAll].astro
#1415531822c3 Thanks @ascorbic! - Fixes a bug that caused an error “serverEntrypointModule[_start] is not a function” in some adapters
#14031e9206c1 Thanks @jp-knj! - Optimized the build pipeline for SVG images. Now, Astro doesn’t reprocess images that have already been processed.
#14132976879a Thanks @ematipico! - Fixes a bug where the property Astro.routePattern/context.routePattern wasn’t updated when using a rewrite via middleware.
#14131aafc4d7 Thanks @florian-lefebvre! - Fixes a case where an error occurring in a middleware would show the dev overlay instead of the custom 500.astro page
#1411914807a4 Thanks @ascorbic! - Fixes a bug that caused builds to fail if a client directive was mistakenly added to an Astro component
#140014b03d9c Thanks @dnek! - Fixes an issue where getImage() assigned the resized base URL to the srcset URL of ImageTransform, which matched the width, height, and format of the original image.
#13971fe35ee2 Thanks @adamhl8! - Adds an experimental flag rawEnvValues to disable coercion of import.meta.env values (e.g. converting strings to other data types) that are populated from process.env
However, Astro also converts your environment variables used through import.meta.env in some cases, and this can prevent access to some values such as the strings "true" (which is converted to a boolean value), and "1" (which is converted to a number).
The experimental.rawEnvValues flag disables coercion of import.meta.env values that are populated from process.env, allowing you to use the raw value.
To enable this feature, add the experimental flag in your Astro config:
import { defineConfig } from "astro/config"
export default defineConfig({
experimental: {
rawEnvValues: true,
}
})
If you were relying on this coercion, you may need to update your project code to apply it manually:
#139416bd5f75 Thanks @aditsachde! - Adds support for TOML files to Astro’s built-in glob() and file() content loaders.
In Astro 5.2, Astro added support for using TOML frontmatter in Markdown files instead of YAML. However, if you wanted to use TOML files as local content collection entries themselves, you needed to write your own loader.
Astro 5.12 now directly supports loading data from TOML files in content collections in both the glob() and the file() loaders.
If you had added your own TOML content parser for the file() loader, you can now remove it as this functionality is now included:
Note that TOML does not support top-level arrays. Instead, the file() loader considers each top-level table to be an independent entry. The table header is populated in the id field of the entry object.
#140453276b79 Thanks @ghubo! - Fixes a problem where importing animated .avif files returns a NoImageMetadata error.
#140410c4d5f8 Thanks @dixslyf! - Fixes a <ClientRouter /> bug where the fallback view transition animations when exiting a page
ran too early for browsers that do not support the View Transition API.
This bug prevented event.viewTransition?.skipTransition() from skipping the page exit animation
when used in an astro:before-swap event hook.
#13972db8f8be Thanks @ematipico! - Updates the NodeApp.match() function in the Adapter API to accept a second, optional parameter to allow adapter authors to add headers to static, prerendered pages.
NodeApp.match(request) currently checks whether there is a route that matches the given Request. If there is a prerendered route, the function returns undefined, because static routes are already rendered and their headers cannot be updated.
When the new, optional boolean parameter is passed (e.g. NodeApp.match(request, true)), Astro will return the first matched route, even when it’s a prerendered route. This allows your adapter to now access static routes and provides the opportunity to set headers for these pages, for example, to implement a Content Security Policy (CSP).
🐞 Patch Changes
#1402942562f9 Thanks @ematipico! - Fixes a bug where server islands wouldn’t be correctly rendered when they are rendered inside fragments.
Now the following examples work as expected:
---
import { Cart } from'../components/Cart.astro';
---
<>
<Cartserver:defer />
</>
<Fragmentslot="rest">
<Cartserver:defer>
<divslot="fallback">Not working</div>
</Cart>
</Fragment>
#140178d238bc Thanks @dmgawel! - Fixes a bug where i18n fallback rewrites didn’t work in dynamic pages.
#140003cbedae Thanks @feelixe! - Fix routePattern JSDoc examples to show correct return values
#13990de6cfd6 Thanks @isVivek99! - Fixes a case where astro:config/client and astro:config/server virtual modules would not contain config passed to integrations updateConfig() during the build
#14019a160d1e Thanks @ascorbic! - Removes the requirement to set type: 'live' when defining experimental live content collections
Previously, live collections required a type and loader configured. Now, Astro can determine that your collection is a live collection without defining it explicitly.
This means it is now safe to remove type: 'live' from your collections defined in src/live.config.ts:
import { defineLiveCollection } from 'astro:content';
import { storeLoader } from '@mystore/astro-loader';
const products = defineLiveCollection({
type: 'live',
loader: storeLoader({
apiKey: process.env.STORE_API_KEY,
endpoint: 'https://api.mystore.com/v1',
}),
});
export const collections = { products };
This is not a breaking change: your existing live collections will continue to work even if you still include type: 'live'. However, we suggest removing this line at your earliest convenience for future compatibility when the feature becomes stable and this config option may be removed entirely.
#13966598da21 Thanks @msamoylov! - Fixes a broken link on the default 404 page in development
#13988609044c Thanks @ascorbic! - Fixes a bug in live collections that caused it to incorrectly complain about the collection being defined in the wrong file
#13909b258d86 Thanks @isVivek99! - Fixes rendering of special boolean attributes for custom elements
#13983e718375 Thanks @florian-lefebvre! - Fixes a case where the toolbar audit would incorrectly flag images processed by Astro in content collections documents
#13999f077b68 Thanks @ascorbic! - Adds lastModified field to experimental live collection cache hints
Live loaders can now set a lastModified field in the cache hints for entries and collections to indicate when the data was last modified. This is then available in the cacheHint field returned by getCollection and getEntry.
#1398708f34b1 Thanks @ematipico! - Adds an informative message in dev mode when the CSP feature is enabled.
#1400582aad62 Thanks @ematipico! - Fixes a bug where inline styles and scripts didn’t work when CSP was enabled. Now when adding <styles> elements inside an Astro component, their hashes care correctly computed.
#13917e615216 Thanks @ascorbic! - Adds a new priority attribute for Astro’s image components.
This change introduces a new priority option for the <Image /> and <Picture /> components, which automatically sets the loading, decoding, and fetchpriority attributes to their optimal values for above-the-fold images which should be loaded immediately.
It is a boolean prop, and you can use the shorthand syntax by simply adding priority as a prop to the <Image /> or <Picture /> component. When set, it will apply the following attributes:
loading="eager"
decoding="sync"
fetchpriority="high"
The individual attributes can still be set manually if you need to customize your images further.
By default, the Astro <Image /> component generates <img> tags that lazy-load their content by setting loading="lazy" and decoding="async". This improves performance by deferring the loading of images that are not immediately visible in the viewport, and gives the best scores in performance audits like Lighthouse.
The new priority attribute will override those defaults and automatically add the best settings for your high-priority assets.
This option was previously available for experimental responsive images, but now it is a standard feature for all images.
<Imagesrc="/path/to/image.jpg"alt="An example image"priority />
[!Note]
You should only use the priority option for images that are critical to the initial rendering of the page, and ideally only one image per page. This is often an image identified as the LCP element when running Lighthouse tests. Using it for too many images will lead to performance issues, as it forces the browser to load those images immediately, potentially blocking the rendering of other content.
#13917e615216 Thanks @ascorbic! - The responsive images feature introduced behind a flag in v5.0.0 is no longer experimental and is available for general use.
The new responsive images feature in Astro automatically generates optimized images for different screen sizes and resolutions, and applies the correct attributes to ensure that images are displayed correctly on all devices.
Enable the image.responsiveStyles option in your Astro config. Then, set a layout attribute on any or component, or configure a default image.layout, for instantly responsive images with automatically generated srcset and sizes attributes based on the image’s dimensions and the layout type.
Displaying images correctly on the web can be challenging, and is one of the most common performance issues seen in sites. This new feature simplifies the most challenging part of the process: serving your site visitor an image optimized for their viewing experience, and for your website’s performance.
The experimental.responsiveImages flag has been removed, and all experimental image configuration options have been renamed to their final names.
If you were using the experimental responsive images feature, you’ll need to update your configuration:
Remove the experimental flag
export default defineConfig({
experimental: {
responsiveImages: true,
},
});
Update image configuration options
During the experimental phase, default styles were applied automatically to responsive images. Now, you need to explicitly set the responsiveStyles option to true if you want these styles applied.
export default defineConfig({
image: {
responsiveStyles: true,
},
});
The experimental image configuration options have been renamed:
responsiveStyles: true, // This is now *false* by default
},
});
Component usage remains the same
The layout, fit, and position props on <Image> and <Picture> components work exactly the same as before:
<Image
src={myImage}
alt="A responsive image"
layout="constrained"
fit="cover"
position="center"
/>
If you weren’t using the experimental responsive images feature, no changes are required.
Please see the Image guide for more information on using responsive images in Astro.
#136853c04c1f Thanks @ascorbic! - Adds experimental support for live content collections
Live content collections are a new type of content collection that fetch their data at runtime rather than build time. This allows you to access frequently-updated data from CMSs, APIs, databases, or other sources using a unified API, without needing to rebuild your site when the data changes.
In Astro 5.0, the content layer API added support for adding diverse content sources to content collections. You can create loaders that fetch data from any source at build time, and then access it inside a page via getEntry() and getCollection(). The data is cached between builds, giving fast access and updates.
However there is no method for updating the data store between builds, meaning any updates to the data need a full site deploy, even if the pages are rendered on-demand. This means that content collections are not suitable for pages that update frequently. Instead, today these pages tend to access the APIs directly in the frontmatter. This works, but leads to a lot of boilerplate, and means users don’t benefit from the simple, unified API that content loaders offer. In most cases users tend to individually create loader libraries that they share between pages.
Live content collections solve this problem by allowing you to create loaders that fetch data at runtime, rather than build time. This means that the data is always up-to-date, without needing to rebuild the site.
To enable live collections add the experimental.liveContentCollections flag to your astro.config.mjs file:
astro.config.mjs
{
experimental: {
liveContentCollections: true,
},
}
Then create a new src/live.config.ts file (alongside your src/content.config.ts if you have one) to define your live collections with a live loader and optionally a schema using the new defineLiveCollection() function from the astro:content module.
#13957304df34 Thanks @ematipico! - Fixes an issue where report-uri wasn’t available in experimental.csp.directives, causing a typing error and a runtime validation error.
#13957304df34 Thanks @ematipico! - Fixes a type error for the CSP directives upgrade-insecure-requests, sandbox, and trusted-type.
#13862fe8f61a Thanks @florian-lefebvre! - Fixes a case where the dev toolbar would crash if it could not retrieve some essential data
#139760a31d99 Thanks @florian-lefebvre! - Fixes a case where Astro Actions types would be broken when using a tsconfig.json with "moduleResolution": "nodenext"
#13923a9ac5ed Thanks @ematipico! - BREAKING CHANGE to the experimental Content Security Policy (CSP) only
Changes the behavior of experimental Content Security Policy (CSP) to now serve hashes differently depending on whether or not a page is prerendered:
Via the <meta> element for static pages.
Via the Response header content-security-policy for on-demand rendered pages.
This new strategy allows you to add CSP content that is not supported in a <meta> element (e.g. report-uri, frame-ancestors, and sandbox directives) to on-demand rendered pages.
No change to your project code is required as this is an implementation detail. However, this will result in a different HTML output for pages that are rendered on demand. Please check your production site to verify that CSP is working as intended.
To keep up to date with this developing feature, or to leave feedback, visit the CSP Roadmap proposal.
#13926953a249 Thanks @ematipico! - Adds a new Astro Adapter Feature called experimentalStaticHeaders to allow your adapter to receive the Headers for rendered static pages.
Adapters that enable support for this feature can access header values directly, affecting their handling of some Astro features such as Content Security Policy (CSP). For example, Astro will no longer serve the CSP <meta http-equiv="content-security-policy"> element in static pages to adapters with this support.
Astro will serve the value of the header inside a map that can be retrieved from the hook astro:build:generated. Adapters can read this mapping and use their hosting headers capabilities to create a configuration file.
A new field called experimentalRouteToHeaders will contain a map of Map<IntegrationResolvedRoute, Headers> where the Headers type contains the headers emitted by the rendered static route.
To enable support for this experimental Astro Adapter Feature, add it to your adapterFeatures in your adapter config:
See the Adapter API docs for more information about providing adapter features.
#13697af83b85 Thanks @benosmac! - Fixes issues with fallback route pattern matching when i18n.routing.fallbackType is rewrite.
Adds conditions for route matching in generatePath when building fallback routes and checking for existing translated pages
Now for a route to be matched it needs to be inside a named [locale] folder. This fixes an issue where route.pattern.test() incorrectly matched dynamic routes, causing the page to be skipped.
Adds conditions for route matching in findRouteToRewrite
Now the requested pathname must exist in route.distURL for a dynamic route to match. This fixes an issue where route.pattern.test() incorrectly matched dynamic routes, causing the build to fail.
#139241cd8c3b Thanks @qw-in! - Fixes an edge case where isPrerendered was incorrectly set to false for static redirects.
#13926953a249 Thanks @ematipico! - Fixes an issue where the experimental CSP meta element wasn’t placed in the <head> element as early as possible, causing these policies to not apply to styles and scripts that came before the meta element.
#13919423fe60 Thanks @ematipico! - Fixes a bug where Astro added quotes to the CSP resources.
Only certain resources require quotes (e.g. 'self' but not https://cdn.example.com), so Astro no longer adds quotes to any resources. You must now provide the quotes yourself for resources such as 'self' when necessary:
export default defineConfig({
experimental: {
csp: {
styleDirective: {
resources: [
"self",
"'self'",
"https://cdn.example.com"
]
}
}
}
})
#1391476c5480 Thanks @ematipico! - BREAKING CHANGE to the experimental Content Security Policy feature only
Removes support for experimental Content Security Policy (CSP) when using the <ClientRouter /> component for view transitions.
It is no longer possible to enable experimental CSP while using Astro’s view transitions. Support was already unstable with the <ClientRouter /> because CSP required making its underlying implementation asynchronous. This caused breaking changes for several users and therefore, this PR removes support completely.
If you are currently using the component for view transitions, please remove the experimental CSP flag as they cannot be used together.
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
csp: true
}
});
Alternatively, to continue using experimental CSP in your project, you can consider migrating to the browser native View Transition API and remove the <ClientRouter /> from your project. You may be able to achieve similar results if you are not using Astro’s enhancements to the native View Transitions and Navigation APIs.
Support might be reintroduced in future releases. You can follow this experimental feature’s development in the CSP RFC.
CSP is an important feature to provide fine-grained control over resources that can or cannot be downloaded and executed by a document. In particular, it can help protect against cross-site scripting (XSS) attacks.
Enabling this feature adds additional security to Astro’s handling of processed and bundled scripts and styles by default, and allows you to further configure these, and additional, content types. This new experimental feature has been designed to work in every Astro rendering environment (static pages, dynamic pages and single page applications), while giving you maximum flexibility and with type-safety in mind.
It is compatible with most of Astro’s features such as client islands, and server islands, although Astro’s view transitions using the <ClientRouter /> are not yet fully supported. Inline scripts are not supported out of the box, but you can provide your own hashes for external and inline scripts.
To enable this feature, add the experimental flag in your Astro config:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
experimental: {
csp: true,
},
});
For more information on enabling and using this feature in your project, see the Experimental CSP docs.
For a complete overview, and to give feedback on this experimental API, see the Content Security Policy RFC.
When creating a content loader, you will now have access to a renderMarkdown function that allows you to render Markdown content directly within your loaders. It uses the same settings and plugins as the renderer used for Markdown files in Astro, and follows any Markdown settings you have configured in your Astro project.
This allows you to render Markdown content from various sources, such as a CMS or other data sources, directly in your loaders without needing to preprocess the Markdown content separately.
importtype { Loader } from'astro/loaders';
import { loadFromCMS } from'./cms';
exportfunctionmyLoader(settings):Loader {
return {
name: 'my-loader',
asyncload({ renderMarkdown, store }) {
constentries=awaitloadFromCMS();
store.clear();
for (constentryof entries) {
// Assume each entry has a 'content' field with markdown content
store.set(entry.id, {
id: entry.id,
data: entry,
rendered: awaitrenderMarkdown(entry.content),
});
}
},
};
}
The return value of renderMarkdown is an object with two properties: html and metadata. These match the rendered property of content entries in content collections, so you can use them to render the content in your components or pages.
#1388762f0668 Thanks @yanthomasdev! - Adds an option for integration authors to suppress adapter warning/errors in supportedAstroFeatures. This is useful when either an warning/error isn’t applicable in a specific context or the default one might conflict and confuse users.
To do so, you can add suppress: "all" (to suppress both the default and custom message) or suppress: "default" (to only suppress the default one):
setAdapter({
name: 'my-astro-integration',
supportedAstroFeatures: {
staticOutput: 'stable',
hybridOutput: 'stable',
sharpImageService: {
support: 'limited',
message:
"The sharp image service isn't available in the deploy environment, but will be used by prerendered pages on build.",
This change adds a new image.experimentalDefaultStyles option that allows you to disable the default styles applied to responsive images.
When using experimental responsive images, Astro applies default styles to ensure the images resize correctly. In most cases this is what you want – and they are applied with low specificity so your own styles override them. However in some cases you may want to disable these default styles entirely. This is particularly useful when using Tailwind 4, because it uses CSS cascade layers to apply styles, making it difficult to override the default styles.
image.experimentalDefaultStyles is a boolean option that defaults to true, so you can change it in your Astro config file like this:
Node.js 18 has now reached end-of-life and should not be used. For now, Astro will continue to support Node.js 18.20.8, which is the final LTS release of Node.js 18, as well as Node.js 20 and Node.js 22 or later. We will drop support for Node.js 18 in a future release, so we recommend upgrading to Node.js 22 as soon as possible. See Astro’s Node.js support policy for more details.
:warning: Important note for users of Cloudflare Pages: The current build image for Cloudflare Pages uses Node.js 18.17.1 by default, which is no longer supported by Astro. If you are using Cloudflare Pages you should override the default Node.js version to Node.js 22. This does not affect users of Cloudflare Workers, which uses Node.js 22 by default.
#1337350ef568 Thanks @jpwienekus! - Fixes a bug where highlights and tooltips render over the audit list window.
#13769e9fc456 Thanks @romanstetsyk! - Expand ActionError codes to include all IANA-registered HTTP error codes.
#13668866285a Thanks @sapphi-red! - Replaces internal CSS chunking behavior for Astro components’ scoped styles to use Vite’s cssScopeTo feature. The feature is a port of Astro’s implementation so this should not change the behavior.
#137887d0b7ac Thanks @florian-lefebvre! - Fixes a case where an error would not be thrown when using the <Font /> component from the experimental fonts API without adding fonts in the Astro config
#13784d7a1889 Thanks @florian-lefebvre! - Fixes the experimental fonts API to correctly take config.base, config.build.assets and config.build.assetsPrefix into account
#13777a56b8ea Thanks @L4Ph! - Fixed an issue where looping GIF animation would stop when converted to WebP
#13752a079c21 Thanks @florian-lefebvre! - Improves handling of font URLs not ending with a file extension when using the experimental fonts API
#137507d3127d Thanks @martrapp! - Allows the ClientRouter to open new tabs or windows when submitting forms by clicking while holding the Cmd, Ctrl, or Shift key.
#13765d874fe0 Thanks @florian-lefebvre! - Fixes a case where font sources with relative protocol URLs would fail when using the experimental fonts API
#136405e582e7 Thanks @florian-lefebvre! - Allows inferring weight and style when using the local provider of the experimental fonts API
If you want Astro to infer those properties directly from your local font files, leave them undefined:
#137515816b8a Thanks @florian-lefebvre! - Updates unifont to support subsets when using the google provider with the experimental fonts API
#13756d4547ba Thanks @florian-lefebvre! - Adds a terminal warning when a remote provider returns no data for a family when using the experimental fonts API
#13742f599463 Thanks @florian-lefebvre! - Fixes optimized fallback css generation to properly add a src when using the experimental fonts API
#137406935540 Thanks @vixalien! - Fix cookies set after middleware did a rewrite with next(url) not being applied
#137594a56d0a Thanks @jp-knj! - Improved the error handling of certain error cases.
#13715b32dffa Thanks @florian-lefebvre! - Updates unifont to fix a case where a unicodeRange related error would be thrown when using the experimental fonts API
#1370528f8716 Thanks @florian-lefebvre! - Updates unifont to latest and adds support for fetch options from remote providers when using the experimental fonts API
#1369260d5be4 Thanks @Le0Developer! - Fixes a bug where Astro couldn’t probably use inferSize for images that contain apostrophe ' in their name.
#13698ab98f88 Thanks @sarah11918! - Improves the configuration reference docs for the adapter entry with more relevant text and links.
#13653a7b2dc6 Thanks @florian-lefebvre! - Reduces the amount of preloaded files for the local provider when using the experimental fonts API
#13653a7b2dc6 Thanks @florian-lefebvre! - Fixes a case where invalid CSS was emitted when using an experimental fonts API family name containing a space
#13703659904b Thanks @florian-lefebvre! - Fixes a bug where empty fallbacks could not be provided when using the experimental fonts API
#1368018e1b97 Thanks @florian-lefebvre! - Improves the UnsupportedExternalRedirect error message to include more details such as the concerned destination
:warning: BREAKING CHANGE FOR EXPERIMENTAL RESPONSIVE IMAGES ONLY :warning:
The generated styles for image layouts are now simpler and easier to override. Previously the responsive image component used CSS to set the size and aspect ratio of the images, but this is no longer needed. Now the styles just include object-fit and object-position for all images, and sets max-width: 100% for constrained images and width: 100% for full-width images.
This is an implementation change only, and most users will see no change. However, it may affect any custom styles you have added to your responsive images. Please check your rendered images to determine whether any change to your CSS is needed.
The styles now use the :where() pseudo-class, which has a specificity of 0, meaning that it is easy to override with your own styles. You can now be sure that your own classes will always override the applied styles, as will global styles on img.
An exception is Tailwind 4, which uses cascade layers, meaning the rules are always lower specificity. Astro supports browsers that do not support cascade layers, so we cannot use this. If you need to override the styles using Tailwind 4, you must use !important classes. Do check if this is needed though: there may be a layout that is more appropriate for your use case.
#13703659904b Thanks @ascorbic! - Adds warnings about using local font files in the publicDir when the experimental fonts API is enabled.
#13703659904b Thanks @ascorbic! - Renames experimental responsive image layout option from “responsive” to “constrained”
:warning: BREAKING CHANGE FOR EXPERIMENTAL RESPONSIVE IMAGES ONLY :warning:
The layout option called "responsive" is renamed to "constrained" to better reflect its behavior.
The previous name was causing confusion, because it is also the name of the feature. The responsive layout option is specifically for images that are displayed at the requested size, unless they do not fit the width of their container, at which point they would be scaled down to fit. They do not get scaled beyond the intrinsic size of the source image, or the width prop if provided.
It became clear from user feedback that many people (understandably) thought that they needed to set layout to responsive if they wanted to use responsive images. They then struggled with overriding styles to make the image scale up for full-width hero images, for example, when they should have been using full-width layout. Renaming the layout to constrained should make it clearer that this layout is for when you want to constrain the maximum size of the image, but allow it to scale-down.
Upgrading
If you set a default image.experimentalLayout in your astro.config.mjs, or set it on a per-image basis using the layout prop, you will need to change all occurences to constrained:
astro.config.mjs
exportdefault {
image: {
experimentalLayout: 'responsive',
experimentalLayout: 'constrained',
},
}
src/pages/index.astro
---
import { Image } from'astro:assets';
---
<Imagesrc="/image.jpg"layout="responsive" />
<Imagesrc="/image.jpg"layout="constrained" />
Please give feedback on the RFC if you have any questions or comments about the responsive images API.
#1366973f24d4 Thanks @ematipico! - Fixes an issue where Astro.originPathname wasn’t returning the correct value when using rewrites.
#1367442388b2 Thanks @florian-lefebvre! - Fixes a case where an experimental fonts API error would be thrown when using another astro:assets API
#136544931457 Thanks @florian-lefebvre! - Fixes fontProviders.google() so it can forward options to the unifont provider, when using the experimental fonts API
#1364367b7493 Thanks @tanishqmanuja! - Fixes a case where the font face src format would be invalid when using the experimental fonts API
#1363923410c6 Thanks @florian-lefebvre! - Fixes a case where some font families would not be downloaded when using the same font provider several times, using the experimental fonts API
#135272fd6a6b Thanks @ascorbic! - The experimental session API introduced in Astro 5.1 is now stable and ready for production use.
Sessions are used to store user state between requests for on-demand rendered pages. You can use them to store user data, such as authentication tokens, shopping cart contents, or any other data that needs to persist across requests:
---
exportconstprerender=false; // Not needed with 'server' output
constcart=await Astro.session.get('cart');
---
<ahref="/checkout">🛒 {cart?.length??0} items</a>
Configuring session storage
Sessions require a storage driver to store the data. The Node, Cloudflare and Netlify adapters automatically configure a default driver for you, but other adapters currently require you to specify a custom storage driver in your configuration.
If you are using an adapter that doesn’t have a default driver, or if you want to choose a different driver, you can configure it using the session configuration option:
import { defineConfig } from'astro/config';
import vercel from'@astrojs/vercel';
exportdefaultdefineConfig({
adapter: vercel(),
session: {
driver: 'upstash',
},
});
Using sessions
Sessions are available in on-demand rendered pages, API endpoints, actions and middleware.
In pages and components, you can access the session using Astro.session:
---
constcart=await Astro.session.get('cart');
---
<ahref="/checkout">🛒 {cart?.length??0} items</a>
In endpoints, actions, and middleware, you can access the session using context.session:
exportasyncfunctionGET(context) {
constcart=await context.session.get('cart');
return Response.json({ cart });
}
If you attempt to access the session when there is no storage driver configured, or in a prerendered page, the session object will be undefined and an error will be logged in the console:
---
exportconstprerender=true;
constcart=await Astro.session?.get('cart'); // Logs an error. Astro.session is undefined
---
Upgrading from Experimental to Stable
If you were previously using the experimental API, please remove the experimental.session flag from your configuration:
#12775b1fe521 Thanks @florian-lefebvre! - Adds a new, experimental Fonts API to provide first-party support for fonts in Astro.
This experimental feature allows you to use fonts from both your file system and several built-in supported providers (e.g. Google, Fontsource, Bunny) through a unified API. Keep your site performant thanks to sensible defaults and automatic optimizations including fallback font generation.
To enable this feature, configure an experimental.fonts object with one or more fonts:
Then, add a <Font /> component and site-wide styling in your <head>:
src/components/Head.astro
---
import { Font } from'astro:assets';
---
<FontcssVariable="--font-roboto"preload />
<style>
body {
font-family: var(--font-roboto);
}
</style>
Visit the experimental Fonts documentation for the full API, how to get started, and even how to build your own custom AstroFontProvider if we don’t yet support your preferred font service.
For a complete overview, and to give feedback on this experimental API, see the Fonts RFC and help shape its future.
#13560df3fd54 Thanks @ematipico! - The virtual module astro:config introduced behind a flag in v5.2.0 is no longer experimental and is available for general use.
This virtual module exposes two sub-paths for type-safe, controlled access to your configuration:
astro:config/client: exposes config information that is safe to expose to the client.
astro:config/server: exposes additional information that is safe to expose to the server, such as file and directory paths.
Access these in any file inside your project to import and use select values from your Astro config:
If you have been waiting for stabilization before using the SVG Components feature, you can now do so.
If you were previously using this feature, please remove the experimental flag from your Astro config:
import { defineConfig } from 'astro'
export default defineConfig({
experimental: {
svg: true,
}
})
Additionally, a few features that were available during the experimental stage were removed in a previous release. Please see the v5.6.0 changelog for details if you have not yet already updated your project code for the experimental feature accordingly.
#136023213450 Thanks @natemoo-re! - Updates the Audit dev toolbar app to automatically strip data-astro-source-file and data-astro-source-loc attributes in dev mode.
#13598f5de51e Thanks @dreyfus92! - Fix routing with base paths when trailingSlash is set to ‘never’. This ensures requests to ‘/base’ are correctly matched when the base path is set to ‘/base’, without requiring a trailing slash.
#13603d038030 Thanks @sarah11918! - Adds the minimal starter template to the list of create astro options
Good news if you’re taking the introductory tutorial in docs, making a minimal reproduction, or just want to start a project with as little to rip out as possible. Astro’s minimal (empty) template is now back as one of the options when running create astro@latest and starting a new project!
#135895a0563d Thanks @ematipico! - Deprecates the asset utility function emitESMImage() and adds a new emitImageMetadata() to be used instead
The function
emitESMImage() is now deprecated. It will continue to function, but it is no longer recommended nor supported. This function will be completely removed in a next major release of Astro.
Please replace it with the new functionemitImageMetadata() as soon as you are able to do so:
import { emitESMImage } from "astro/assets/utils";
import { emitImageMetadata } from "astro/assets/utils";
The new function returns the same signature as the previous one. However, the new function removes two deprecated arguments that were not meant to be exposed for public use: _watchMode and experimentalSvgEnabled. Since it was possible to access these with the old function, you may need to verify that your code still works as intended with emitImageMetadata().
Deno requires npm prefix to install packages on npm. For example, to install react, we need to run deno add npm:react. But currently the command executed is deno add react, which doesn’t work. So, we change the package names to have an npm prefix if you are using Deno.
#13587a0774b3 Thanks @robertoms99! - Fixes an issue with the client router where some attributes of the root element were not updated during swap, including the transition scope.
#13545a7aff41 Thanks @stramel! - Prevent empty attributes from appearing in the SVG output
#135529cd0fd4 Thanks @ematipico! - Fixes an issue where Astro validated the i18n configuration incorrectly, causing false positives in downstream libraries.
#13403dcb9526 Thanks @yurynix! - Adds a new optional prerenderedErrorPageFetch option in the Adapter API to allow adapters to provide custom implementations for fetching prerendered error pages.
Now, adapters can override the default fetch() behavior, for example when fetch() is unavailable or when you cannot call the server from itself.
The following example provides a custom fetch for 500.html and 404.html, reading them from disk instead of performing an HTTP call:
#13482ff257df Thanks @florian-lefebvre! - Updates Astro config validation to also run for the Integration API. An error log will specify which integration is failing the validation.
Now, Astro will first validate the user configuration, then validate the updated configuration after each integration astro:config:setup hook has run. This means updateConfig() calls will no longer accept invalid configuration.
This fixes a situation where integrations could potentially update a project with a malformed configuration. These issues should now be caught and logged so that you can update your integration to only set valid configurations.
#1340521e7e80 Thanks @Marocco2! - Adds a new eagerness option for prefetch() when using experimental.clientPrerender
With the experimental clientPrerender flag enabled, you can use the eagerness option on prefetch() to suggest to the browser how eagerly it should prefetch/prerender link targets.
This follows the same API described in the Speculation Rules API and allows you to balance the benefit of reduced wait times against bandwidth, memory, and CPU costs for your site visitors.
For example, you can now use prefetch() programmatically with large sets of links and avoid browser limits in place to guard against over-speculating (prerendering/prefetching too many links). Set eagerness: 'moderate' to take advantage of First In, First Out (FIFO) strategies and browser heuristics to let the browser decide when to prerender/prefetch them and in what order:
<aclass="link-moderate"href="/nice-link-1">A Nice Link 1</a>
<aclass="link-moderate"href="/nice-link-2">A Nice Link 2</a>
<aclass="link-moderate"href="/nice-link-3">A Nice Link 3</a>
<aclass="link-moderate"href="/nice-link-4">A Nice Link 4</a>
...
<aclass="link-moderate"href="/nice-link-20">A Nice Link 20</a>
If an error is thrown from an integration hook, an error log will now provide information about the concerned integration and hook
🐞 Patch Changes
#13539c43bf8c Thanks @ascorbic! - Adds a new session.load() method to the experimental session API that allows you to load a session by ID.
When using the experimental sessions API, you don’t normally need to worry about managing the session ID and cookies: Astro automatically reads the user’s cookies and loads the correct session when needed. However, sometimes you need more control over which session to load.
The new load() method allows you to manually load a session by ID. This is useful if you are handling the session ID yourself, or if you want to keep track of a session without using cookies. For example, you might want to restore a session from a logged-in user on another device, or work with an API endpoint that doesn’t use cookies.
#13488d777420 Thanks @stramel! - BREAKING CHANGE to the experimental SVG Component API only
Removes some previously available prop, attribute, and configuration options from the experimental SVG API. These items are no longer available and must be removed from your code:
The title prop has been removed until we can settle on the correct balance between developer experience and accessibility. Please replace any title props on your components with aria-label:
<Logo title="My Company Logo" />
<Logo aria-label="My Company Logo" />
Sprite mode has been temporarily removed while we consider a new implementation that addresses how this feature was being used in practice. This means that there are no longer multiple mode options, and all SVGs will be inline. All instances of mode must be removed from your project as you can no longer control a mode:
<Logo mode="inline" />
<Logo />
import { defineConfig } from 'astro'
export default defineConfig({
experimental: {
svg: {
mode: 'sprite'
},
svg: true
}
});
The default role is no longer applied due to developer feedback. Please add the appropriate role on each component individually as needed:
<Logo />
<Logo role="img" /> // To keep the role that was previously applied by default
The size prop has been removed to better work in combination with viewBox and additional styles/attributes. Please replace size with explicit width and height attributes:
#1342906de673 Thanks @ematipico! - The ActionAPIContext.rewrite method is deprecated and will be removed in a future major version of Astro
#1352482cd583 Thanks @ematipico! - Fixes a bug where the functions Astro.preferredLocale and Astro.preferredLocaleList would return the incorrect locales
when the Astro configuration specifies a list of codes. Before, the functions would return the path, instead now the functions
return a list built from codes.
#13483fc2dcb8 Thanks @ematipico! - Fixes a bug where an Astro adapter couldn’t call the middleware when there isn’t a route that matches the incoming request.
#133727783dbf Thanks @ascorbic! - Fixes a bug that caused some very large data stores to save incomplete data.
#133588c21663 Thanks @ematipico! - Adds a new function called insertPageRoute to the Astro Container API.
The new function is useful when testing routes that, for some business logic, use Astro.rewrite.
For example, if you have a route /blog/post and for some business decision there’s a rewrite to /generic-error, the container API implementation will look like this:
console.log(result); // this should print the response from GenericError.astro
This new method only works for page routes, which means that endpoints aren’t supported.
#13426565583b Thanks @ascorbic! - Fixes a bug that caused the astro add command to ignore the --yes flag for third-party integrations
#134289cac9f3 Thanks @matthewp! - Prevent bad value in x-forwarded-host from crashing request
#13432defad33 Thanks @P4tt4te! - Fix an issue in the Container API, where the renderToString function doesn’t render adequately nested slots when they are components.
#13415be866a1 Thanks @ascorbic! - Reuses experimental session storage object between requests. This prevents memory leaks and improves performance for drivers that open persistent connections to a database.
#134202f039b9 Thanks @ematipico! - It fixes an issue that caused some regressions in how styles are bundled.
#134023e7b498 Thanks @ematipico! - Adds a new experimental flag called experimental.preserveScriptOrder that renders <script> and <style> tags in the same order as they are defined.
When rendering multiple <style> and <script> tags on the same page, Astro currently reverses their order in your generated HTML output. This can give unexpected results, for example CSS styles being overridden by earlier defined style tags when your site is built.
With the new preserveScriptOrder flag enabled, Astro will generate the styles in the order they are defined:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
experimental: {
preserveScriptOrder: true,
},
});
For example, the following component has two <style> tags, and both define the same style for the body tag:
<p>I am a component</p>
<style>
body {
background: red;
}
</style>
<style>
body {
background: yellow;
}
</style>
Once the project is compiled, Astro will create an inline style where yellow appears first, and then red. Ultimately, the red background is applied:
body {
background: #ff0;
}
body {
background: red;
}
When experimental.preserveScriptOrder is set to true, the order of the two styles is kept as it is, and in the style generated red appears first, and then yellow:
body {
background: red;
}
body {
background: #ff0;
}
This is a breaking change to how Astro renders project code that contains multiple <style> and <script> tags in the same component. If you were previously compensating for Astro’s behavior by writing these out of order, you will need to update your code.
This will eventually become the new default Astro behavior, so we encourage you to add this experimental style and script ordering as soon as you are able! This will help us test the new behavior and ensure your code is ready when this becomes the new normal.
#13352cb886dc Thanks @delucis! - Adds support for a new experimental.headingIdCompat flag
By default, Astro removes a trailing - from the end of IDs it generates for headings ending with
special characters. This differs from the behavior of common Markdown processors.
You can now disable this behavior with a new configuration flag:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
experimental: {
headingIdCompat: true,
},
});
This can be useful when heading IDs and anchor links need to behave consistently across your site
and other platforms such as GitHub and npm.
#13311a3327ff Thanks @chrisirhc! - Adds a new configuration option for Markdown syntax highlighting excludeLangs
This option provides better support for diagramming tools that rely on Markdown code blocks, such as Mermaid.js and D2 by allowing you to exclude specific languages from Astro’s default syntax highlighting.
This option allows you to avoid rendering conflicts with tools that depend on the code not being highlighted without forcing you to disable syntax highlighting for other code blocks.
The following example configuration will exclude highlighting for mermaid and math code blocks:
#134044e78b4d Thanks @ascorbic! - Fixes a bug in error handling that saving a content file with a schema error would display an “unhandled rejection” error instead of the correct schema error
#13379d59eb22 Thanks @martrapp! - Fixes an edge case where the client router executed scripts twice when used with a custom swap function that only swaps parts of the DOM.
#133936b8fdb8 Thanks @renovate! - Updates primsjs to version 1.30.0, which adds support for more languages and fixes a security advisory which does not affect Astro.
#133747b75bc5 Thanks @ArmandPhilippot! - Fixes the documentation of the i18n configuration where manual was presented as a key of routing instead of an available value.
#133809bfa6e6 Thanks @martrapp! - Fixes an issue where astro:page-load fires before all scripts are executed
#13381249d52a Thanks @martrapp! - Adds the types property to the viewTransition object when the ClientRouter simulates parts of the View Transition API on browsers w/o native support.
#133673ce4ad9 Thanks @ematipico! - Adds documentation to various utility functions used for remote image services
#13347d83f92a Thanks @bluwy! - Updates internal CSS chunking behavior for Astro components’ scoped styles. This may result in slightly more CSS chunks created, but should allow the scoped styles to only be included on pages that use them.
#13388afadc70 Thanks @ematipico! - Fixes a bug where astro:config/server and astro:config/client had incorrect types.
#13355042d1de Thanks @ematipico! - Adds documentation to the assets utilities for remote service images.
#133956d1c63f Thanks @bluwy! - Uses package-manager-detector to detect the package manager used in the project
#13363a793636 Thanks @ematipico! - Fixes an issue where the internal function makeSvgComponent was incorrectly exposed as a public API.
#132620025df3 Thanks @ematipico! - Refactor Astro Actions to not use a middleware. Doing so should avoid unexpected issues when using the Astro middleware at the edge.
#133368f632ef Thanks @ematipico! - Fixes a regression where some asset utilities were move across monorepo, and not re-exported anymore.
#13320b5dabe9 Thanks @{! - Adds support for typing experimental session data
You can add optional types to your session data by creating a src/env.d.ts file in your project that extends the global App.SessionData interface. For example:
declarenamespaceApp {
interfaceSessionData {
id:string;
email:string;
};
lastLogin: Date;
}
}
Any keys not defined in this interface will be treated as any.
Then when you access Astro.session in your components, any defined keys will be typed correctly:
#133305e7646e Thanks @ematipico! - Fixes an issue with the conditional rendering of scripts.
This change updates a v5.0 breaking change when experimental.directRenderScript became the default script handling behavior.
If you have already successfully upgraded to Astro v5, you may need to review your script tags again and make sure they still behave as desired after this release. See the v5 Upgrade Guide for more details.
Two new helper functions exported from astro/config:
mergeConfig() allows users to merge partially defined Astro configurations on top of a base config while following the merge rules of updateConfig() available for integrations.
validateConfig() allows users to validate that a given value is a valid Astro configuration and fills in default values as necessary.
These helpers are particularly useful for integration authors and for developers writing scripts that need to manipulate Astro configurations programmatically.
Programmatic build
The build API now receives a second optional BuildOptions argument where users can specify:
devOutput (default false): output a development-based build similar to code transformed in astro dev.
teardownCompiler (default true): teardown the compiler WASM instance after build.
These options provide more control when running Astro builds programmatically, especially for testing scenarios or custom build pipelines.
#132784a43c4b Thanks @ematipico! - Adds a new configuration option server.allowedHosts and CLI option --allowed-hosts.
Now you can specify the hostnames that the dev and preview servers are allowed to respond to. This is useful for allowing additional subdomains, or running the dev server in a web container.
allowedHosts checks the Host header on HTTP requests from browsers and if it doesn’t match, it will reject the request to prevent CSRF and XSS attacks.
#132541e11f5e Thanks @p0lyw0lf! - Adds the ability to process and optimize remote images in Markdown files
Previously, Astro only allowed local images to be optimized when included using ![]() syntax in plain Markdown files. Astro’s image service could only display remote images without any processing.
Now, Astro’s image service can also optimize remote images written in standard Markdown syntax. This allows you to enjoy the benefits of Astro’s image processing when your images are stored externally, for example in a CMS or digital asset manager.
No additional configuration is required to use this feature! Any existing remote images written in Markdown will now automatically be optimized. To opt-out of this processing, write your images in Markdown using the HTML <img> tag instead. Note that images located in your public/ folder are still never processed.
🐞 Patch Changes
#13256509fa67 Thanks @p0lyw0lf! - Adds experimental responsive image support in Markdown
Previously, the experimental.responsiveImages feature could only provide responsive images when using the <Image /> and <Picture /> components.
Now, images written with the ![]() Markdown syntax in Markdown and MDX files will generate responsive images by default when using this experimental feature.
To try this experimental feature, set experimental.responsiveImages to true in your astro.config.mjs file:
For a complete overview, and to give feedback on this experimental API, see the Responsive Images RFC.
#1332380926fa Thanks @ematipico! - Updates esbuild and vite to the latest to avoid false positives audits warnings caused by esbuild.
#133139e7c71d Thanks @martrapp! - Fixes an issue where a form field named “attributes” shadows the form.attributes property.
#120525be12b2 Thanks @Fryuni! - Fixes incorrect config update when calling updateConfig from astro:build:setup hook.
The function previously called a custom update config function made for merging an Astro config. Now it calls the appropriate mergeConfig() utility exported by Vite that updates functional options correctly.
#133035f72a58 Thanks @ematipico! - Fixes an issue where the dev server was applying second decoding of the URL of the incoming request, causing issues for certain URLs.
#1323332fafeb Thanks @joshmkennedy! - Ensures that Astro.url/ctx.url is correctly updated with the base path after rewrites.
This change fixes an issue where Astro.url/ctx.url did not include the configured base path after Astro.rewrite was called. Now, the base path is correctly reflected in Astro.url.
Previously, any rewrites performed through Astro.rewrite/ctx.rewrite failed to append the base path to Astro.url/ctx.rewrite, which could lead to incorrect URL handling in downstream logic. By fixing this, we ensure that all routes remain consistent and predictable after a rewrite.
If you were relying on the work around of including the base path in astro.rewrite you can now remove it from the path.
#13210344e9bc Thanks @VitaliyR! - Handle HEAD requests to an endpoint when a handler is not defined.
If an endpoint defines a handler for GET, but does not define a handler for HEAD, Astro will call the GET handler and return the headers and status but an empty body.
#131953b66955 Thanks @MatthewLymer! - Improves SSR performance for synchronous components by avoiding the use of Promises. With this change, SSR rendering of on-demand pages can be up to 4x faster.
#131458d4e566 Thanks @ascorbic! - Adds support for adapters auto-configuring experimental session storage drivers.
Adapters can now configure a default session storage driver when the experimental.session flag is enabled. If a hosting platform has a storage primitive that can be used for session storage, the adapter can automatically configure the session storage using that driver. This allows Astro to provide a more seamless experience for users who want to use sessions without needing to manually configure the session storage.
🐞 Patch Changes
#131458d4e566 Thanks @ascorbic! - :warning: BREAKING CHANGE FOR EXPERIMENTAL SESSIONS ONLY :warning:
Changes the experimental.session option to a boolean flag and moves session config to a top-level value. This change is to allow the new automatic session driver support. You now need to separately enable the experimental.session flag, and then configure the session driver using the top-level session key if providing manual configuration.
defineConfig({
// ...
experimental: {
session: {
driver: 'upstash',
},
session: true,
},
session: {
driver: 'upstash',
},
});
You no longer need to configure a session driver if you are using an adapter that supports automatic session driver configuration and wish to use its default settings.
defineConfig({
adapter: node({
mode: "standalone",
}),
experimental: {
session: {
driver: 'fs',
cookie: 'astro-cookie',
},
session: true,
},
session: {
cookie: 'astro-cookie',
},
});
However, you can still manually configure additional driver options or choose a non-default driver to use with your adapter with the new top-level session config option. For more information, see the experimental session docs.
#131012ed67d5 Thanks @corneliusroemer! - Fixes a bug where HEAD and OPTIONS requests for non-prerendered pages were incorrectly rejected with 403 FORBIDDEN
#13133e76aa83 Thanks @ematipico! - Fixes a bug where Astro was failing to build an external redirect when the middleware was triggered
#13119ac43580 Thanks @Hacksore! - Adds extra guidance in the terminal when using the astro add tailwind CLI command
Now, users are given a friendly reminder to import the stylesheet containing their Tailwind classes into any pages where they want to use Tailwind. Commonly, this is a shared layout component so that Tailwind styling can be used on multiple pages.
#131133a26e45 Thanks @unprintable123! - Fixes the bug that rewrite will pass encoded url to the dynamic routing and cause params mismatch.
#1311123978dd Thanks @ascorbic! - Fixes a bug that caused injected endpoint routes to return not found when trailingSlash was set to always
#131120fa5c82 Thanks @ematipico! - Fixes a bug where the i18n middleware was blocking a server island request when the prefixDefaultLocale option is set to true
When the trailingSlash option is set to always or never, on-demand rendered pages will now redirect to the correct URL when the trailing slash doesn’t match the configuration option. This was previously the case for static pages, but now works for on-demand pages as well.
Now, it doesn’t matter whether your visitor navigates to /about/, /about, or even /about///. In production, they’ll always end up on the correct page. For GET requests, the redirect will be a 301 (permanent) redirect, and for all other request methods, it will be a 308 (permanent, and preserve the request method) redirect.
In development, you’ll see a helpful 404 page to alert you of a trailing slash mismatch so you can troubleshoot routes.
Now, you can redirect routes either internally to another path or externally by providing a URL beginning with http or https:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
redirects: {
'/blog': 'https://example.com/blog',
'/news': {
status: 302,
destination: 'https://example.com/news',
},
},
});
#130840f3be31 Thanks @ematipico! - Adds a new experimental virtual module astro:config that exposes a type-safe subset of your astro.config.mjs configuration
The virtual module exposes two sub-paths for controlled access to your configuration:
astro:config/client: exposes config information that is safe to expose to the client.
astro:config/server: exposes additional information that is safe to expose to the server, such as file/dir paths.
To enable this new virtual module, add the experimental.serializeManifest feature flag to your Astro config:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
experimental: {
serializeManifest: true,
},
});
Then, you can access the module in any file inside your project to import and use values from your Astro config:
For a complete overview, and to give feedback on this experimental API, see the Serialized Manifest RFC.
🐞 Patch Changes
#130492ed4bd9 Thanks @florian-lefebvre! - Updates astro add tailwind to add the @tailwindcss/vite plugin instead of the @astrojs/tailwind integration
#129945361755 Thanks @ascorbic! - Returns a more helpful 404 page in dev if there is a trailing slash mismatch between the route requested and the trailingSlash configuration
#12666037495d Thanks @Thodor12! - Added additional generated typings for the content layer
#13059e36837f Thanks @ascorbic! - Fixes a bug that caused tsconfig path aliases to break if there was more than one wildcard pattern
#13045c7f1366 Thanks @mtwilliams-code! - Fixes a bug where the some utility functions of the astro:i18n virtual module would return an incorrect result when trailingSlash is set to never
#129868911bda Thanks @wetheredge! - Updates types and dev toolbar for ARIA 1.2 attributes and roles
#128928f520f1 Thanks @louisescher! - Adds a more descriptive error when a content collection entry has an invalid ID.
#13031f576519 Thanks @florian-lefebvre! - Updates the server islands encoding logic to only escape the script end tag open delimiter and opening HTML comment syntax
#130261d272f6 Thanks @ascorbic! - Fixes a regression that prevented the import of Markdown files as raw text or URLs.
#129989ce0038 Thanks @Kynson! - Fixes the issue that audit incorrectly flag images as above the fold when the scrolling container is not body
#129902e12f1d Thanks @ascorbic! - Fixes a bug that caused references to be incorrectly reported as invalid
#129842d259cf Thanks @ascorbic! - Fixes a bug in dev where files would stop being watched if the Astro config file was edited
#129842d259cf Thanks @ascorbic! - Fixes a bug where the content layer would use an outdated version of the Astro config if it was edited in dev
#12982429aa75 Thanks @bluwy! - Fixes an issue where server islands do not work in projects that use an adapter but only have prerendered pages. If an adapter is added, the server island endpoint will now be added by default.
#1299578fd73a Thanks @florian-lefebvre! - Fixes a case where astro:actions types would not work when using src/actions.ts
#12733bbf1d88 Thanks @ascorbic! - Fixes a bug that caused the dev server to return an error if requesting ”//”
#13001627aec3 Thanks @ascorbic! - Fixes a bug that caused Astro to attempt to inject environment variables into non-source files, causing performance problems and broken builds
#129801a026af Thanks @florian-lefebvre! - Fixes a case where setting the status of a page to 404 in development would show the default 404 page (or custom one if provided) instead of using the current page
#12934673a518 Thanks @ematipico! - Fixes a regression where the Astro Container didn’t work during the build, using pnpm
#12955db447f2 Thanks @martrapp! - Lets TypeScript know about the “blocking” and “disabled” attributes of the <link> element.
#12922faf74af Thanks @adamchal! - Improves performance of static asset generation by fixing a bug that caused image transforms to be performed serially. This fix ensures that processing uses all CPUs when running in a multi-core environment.
#129473c2292f Thanks @ascorbic! - Fixes a bug that caused empty content collections when running dev with NODE_ENV set
#12927ad2a752 Thanks @ematipico! - Fixes a bug where Astro attempted to decode a request URL multiple times, resulting in an unexpected behaviour when decoding the character %
#129120c0c66b Thanks @florian-lefebvre! - Improves the config error for invalid combinations of context and access properties under env.schema
#129353d47e6b Thanks @AirBorne04! - Fixes an issue where Astro.locals coming from an adapter weren’t available in the 404.astro, when using the astro dev command,
#1292544841fc Thanks @ascorbic! - Ensures image styles are not imported unless experimental responsive images are enabled
#129268e64bb7 Thanks @oliverlynch! - Improves remote image cache efficiency by separating image data and metadata into a binary and sidecar JSON file.
#129208b9d530 Thanks @bluwy! - Processes markdown with empty body as remark and rehype plugins may add additional content or frontmatter
#12918fd12a26 Thanks @lameuler! - Fixes a bug where the logged output path does not match the actual output path when using build.format: 'preserve'
#126762ffc0fc Thanks @koyopro! - Allows configuring Astro modules TypeScript compilation with the vite.esbuild config
#12938dbb04f3 Thanks @ascorbic! - Fixes a bug where content collections would sometimes appear empty when first running astro dev
#1293730edb6d Thanks @ematipico! - Fixes a bug where users could use Astro.request.headers during a rewrite inside prerendered routes. This an invalid behaviour, and now Astro will show a warning if this happens.
#1293730edb6d Thanks @ematipico! - Fixes an issue where the use of Astro.rewrite would trigger the invalid use of Astro.request.headers
#1287773a0788 Thanks @bluwy! - Fixes sourcemap warning generated by the astro:server-islands Vite plugin
#129062d89492 Thanks @ascorbic! - Fixes a bug that caused pages that return an empty array from getStaticPath to match every path
011fa0f Thanks @florian-lefebvre! - Fixes a case where astro:content types would be erased when restarting the dev server
#12907dbf1275 Thanks @florian-lefebvre! - Fixes a regression around the server islands route, which was not passed to the adapters astro:build:done hook
#12818579bd93 Thanks @ascorbic! - Fixes race condition where dev server would attempt to load collections before the content had loaded
#12883fbac92f Thanks @kaytwo! - Fixes a bug where responses can be returned before session data is saved
#128153acc654 Thanks @ericswpark! - Some non-index files that were incorrectly being treated as index files are now excluded
#1278196c4b92 Thanks @ascorbic! - Fixes a regression that caused default() to not work with reference()
#12820892dd9f Thanks @ascorbic! - Fixes a bug that caused cookies to not be deleted when destroying a session
#12864440d8a5 Thanks @kaytwo! - Fixes a bug where the session ID wasn’t correctly regenerated
#12768524c855 Thanks @ematipico! - Fixes an issue where Astro didn’t print error logs when Astro Islands were used in incorrect cases.
#12814f12f111 Thanks @ematipico! - Fixes an issue where Astro didn’t log anything in case a file isn’t created during the build.
#12875e109002 Thanks @ascorbic! - Fixes a bug in emulated legacy collections where the entry passed to the getCollection filter function did not include the legacy entry fields.
#12768524c855 Thanks @ematipico! - Fixes an issue where Astro was printing the incorrect output format when running the astro build command
#1281070a9f0b Thanks @louisescher! - Fixes server islands failing to check content-type header under certain circumstances
Sometimes a reverse proxy or similar service might modify the content-type header to include the charset or other parameters in the media type of the response. This previously wasn’t handled by the client-side server island script and thus removed the script without actually placing the requested content in the DOM. This fix makes it so the script checks if the header starts with the proper content type instead of exactly matching text/html, so the following will still be considered a valid header: text/html; charset=utf-8
#128167fb2184 Thanks @ematipico! - Fixes an issue where an injected route entrypoint wasn’t correctly marked because the resolved file path contained a query parameter.
This fixes some edge case where some injected entrypoint were not resolved when using an adapter.
Sessions are used to store user state between requests for server-rendered pages, such as login status, shopping cart contents, or other user-specific data.
---
exportconstprerender=false; // Not needed in 'server' mode
constcart=await Astro.session.get('cart');
---
<ahref="/checkout">🛒 {cart?.length??0} items</a>
Sessions are available in on-demand rendered/SSR pages, API endpoints, actions and middleware. To enable session support, you must configure a storage driver.
If you are using the Node.js adapter, you can use the fs driver to store session data on the filesystem:
astro.config.mjs
{
adapter: node({ mode: 'standalone' }),
experimental: {
session: {
// Required: the name of the unstorage driver
driver: "fs",
},
},
}
If you are deploying to a serverless environment, you can use drivers such as redis, netlify-blobs, vercel-kv, or cloudflare-kv-binding and optionally pass additional configuration options.
For more information, including using the session API with other adapters and a full list of supported drivers, see the docs for experimental session support. For even more details, and to leave feedback and participate in the development of this feature, the Sessions RFC.
Astro 5.1 introduces a new helper function, getActionPath() to give you more flexibility when calling your action.
Calling getActionPath() with your action returns its URL path so you can make a fetch() request with custom headers, or use your action with an API such as navigator.sendBeacon(). Then, you can handle the custom-formatted returned data as needed, just as if you had called an action directly.
This example shows how to call a defined like action passing the Authorization header and the keepalive option:
#12786e56af4a Thanks @ematipico! - Fixes an issue where Astro i18n didn’t properly show the 404 page when using fallback and the option prefixDefaultLocale set to true.
#127638da2318 Thanks @rbsummers! - Fixed changes to vite configuration made in the astro:build:setup integration hook having no effect when target is “client”
#1276736c1e06 Thanks @ascorbic! - Clears the content layer cache when the Astro config is changed
#12597564ac6c Thanks @florian-lefebvre! - Fixes an issue where image and server islands routes would not be passed to the astro:routes:resolved hook during builds
#12718ccc5ad1 Thanks @ematipico! - Fixes an issue where Astro couldn’t correctly handle i18n fallback when using the i18n middleware
#12728ee66a45 Thanks @argyleink! - Adds type support for the closedby attribute for <dialog> elements
#12709e3bfd93 Thanks @mtwilliams-code! - Fixes a bug where Astro couldn’t correctly parse params and props when receiving i18n fallback URLs
#126458704c54 Thanks @sarah11918! - Updates some reference links in error messages for new v5 docs.
#1264148ca399 Thanks @ascorbic! - Fixes a bug where astro info --copy wasn’t working correctly on macOS systems.
#1246162939ad Thanks @kyr0! - Removes the misleading log message telling that a custom renderer is not recognized while it clearly is and works.
#12642ff18b9c Thanks @ematipico! - Provides more information when logging a warning for accessing Astro.request.headers in prerendered pages
#1263403958d9 Thanks @delucis! - Improves error message formatting for user config and content collection frontmatter
#125476b6e18d Thanks @mtwilliams-code! - Fixes a bug where URL search parameters weren’t passed when using the i18n fallback feature.
#12449e6b8017 Thanks @apatel369! - Fixes an issue where the custom assetFileNames configuration caused assets to be incorrectly moved to the server directory instead of the client directory, resulting in 404 errors when accessed from the client side.
#12518e216250 Thanks @ematipico! - Fixes an issue where SSR error pages would return duplicated custom headers.
#1262574bfad0 Thanks @ematipico! - Fixes an issue where the experimental.svg had incorrect type, resulting in some errors in the editors.
#12631dec0305 Thanks @ascorbic! - Fixes a bug where the class attribute was rendered twice on the image component
#126230e4fecb Thanks @ascorbic! - Correctly handles images in content collections with uppercase file extensions
#126338a551c1 Thanks @bluwy! - Cleans up content layer sync during builds and programmatic sync() calls
#1264022e405a Thanks @ascorbic! - Fixes a bug that caused content collections to be returned empty when run in a test environment
#12613306c9f9 Thanks @matthewp! - Fix use of cloned requests in middleware with clientAddress
When using context.clientAddress or Astro.clientAddress Astro looks up the address in a hidden property. Cloning a request can cause this hidden property to be lost.
The fix is to pass the address as an internal property instead, decoupling it from the request.
The previously experimental feature globalRoutePriority is now the default in Astro 5.
This was a refactoring of route prioritization in Astro, making it so that injected routes, file-based routes, and redirects are all prioritized using the same logic. This feature has been enabled for all Starlight projects since it was added and should not affect most users.
#11864ee38b3a Thanks @ematipico! - ### [changed]: entryPoint type inside the hook astro:build:ssr
In Astro v4.x, the entryPoint type was RouteData.
Astro v5.0 the entryPoint type is IntegrationRouteData, which contains a subset of the RouteData type. The fields isIndex and fallbackRoutes were removed.
What should I do?
Update your adapter to change the type of entryPoint from RouteData to IntegrationRouteData.
import type {RouteData} from 'astro';
import type {IntegrationRouteData} from "astro"
function useRoute(route: RouteData) {
function useRoute(route: IntegrationRouteData) {
}
#125249f44019 Thanks @bluwy! - Bumps Vite to ^6.0.1 and handles its breaking changes
#10742b6fbdaa Thanks @ematipico! - The lowest version of Node supported by Astro is now Node v18.17.1 and higher.
#1191646ea29f Thanks @bluwy! - Updates how the build.client and build.server option values get resolved to match existing documentation. With this fix, the option values will now correctly resolve relative to the outDir option. So if outDir is set to ./dist/nested/, then by default:
build.client will resolve to <root>/dist/nested/client/
build.server will resolve to <root>/dist/nested/server/
Previously the values were incorrectly resolved:
build.client was resolved to <root>/dist/nested/dist/client/
build.server was resolved to <root>/dist/nested/dist/server/
If you were relying on the previous build paths, make sure that your project code is updated to the new build paths.
#11982d84e444 Thanks @Princesseuh! - Adds a default exclude and include value to the tsconfig presets. {projectDir}/dist is now excluded by default, and {projectDir}/.astro/types.d.ts and {projectDir}/**/* are included by default.
Both of these options can be overridden by setting your own values to the corresponding settings in your tsconfig.json file.
#118613ab3b4e Thanks @bluwy! - Cleans up Astro-specfic metadata attached to vfile.data in Remark and Rehype plugins. Previously, the metadata was attached in different locations with inconsistent names. The metadata is now renamed as below:
The types of imagePaths has also been updated from Set<string> to string[]. The vfile.data.astro.frontmatter metadata is left unchanged.
While we don’t consider these APIs public, they can be accessed by Remark and Rehype plugins that want to re-use Astro’s metadata. If you are using these APIs, make sure to access them in the new locations.
Middleware, API endpoints, and pages can no longer override the locals object in its entirety. You can still append values onto the object, but you can not replace the entire object and delete its existing values.
If you were previously overwriting like so:
ctx.locals = {
one: 1,
two: 2,
};
This can be changed to an assignment on the existing object instead:
Object.assign(ctx.locals, {
one: 1,
two: 2,
});
#11908518433e Thanks @Princesseuh! - The image.endpoint config now allow customizing the route of the image endpoint in addition to the entrypoint. This can be useful in niche situations where the default route /_image conflicts with an existing route or your local server setup.
import { defineConfig } from'astro/config';
defineConfig({
image: {
endpoint: {
route: '/image',
entrypoint: './src/image_endpoint.ts',
},
},
});
#120085608338 Thanks @Princesseuh! - Welcome to the Astro 5 beta! This release has no changes from the latest alpha of this package, but it does bring us one step closer to the final, stable release.
Starting from this release, no breaking changes will be introduced unless absolutely necessary.
#11679ea71b90 Thanks @florian-lefebvre! - The astro:env feature introduced behind a flag in v4.10.0 is no longer experimental and is available for general use. If you have been waiting for stabilization before using astro:env, you can now do so.
This feature lets you configure a type-safe schema for your environment variables, and indicate whether they should be available on the server or the client.
To configure a schema, add the env option to your Astro config and define your client and server variables. If you were previously using this feature, please remove the experimental flag from your Astro config and move your entire env configuration unchanged to a top-level option.
#11806f7f2338 Thanks @Princesseuh! - Removes the assets property on supportedAstroFeatures for adapters, as it did not reflect reality properly in many cases.
Now, relating to assets, only a single sharpImageService property is available, determining if the adapter is compatible with the built-in sharp image service.
#11864ee38b3a Thanks @ematipico! - ### [changed]: routes type inside the hook astro:build:done
In Astro v4.x, the routes type was RouteData.
Astro v5.0 the routes type is IntegrationRouteData, which contains a subset of the RouteData type. The fields isIndex and fallbackRoutes were removed.
What should I do?
Update your adapter to change the type of routes from RouteData to IntegrationRouteData.
import type {RouteData} from 'astro';
import type {IntegrationRouteData} from "astro"
function useRoute(route: RouteData) {
function useRoute(route: IntegrationRouteData) {
}
#11941b6a5f39 Thanks @Princesseuh! - Merges the output: 'hybrid' and output: 'static' configurations into one single configuration (now called 'static') that works the same way as the previous hybrid option.
It is no longer necessary to specify output: 'hybrid' in your Astro config to use server-rendered pages. The new output: 'static' has this capability included. Astro will now automatically provide the ability to opt out of prerendering in your static site with no change to your output configuration required. Any page route or endpoint can include export const prerender = false to be server-rendered, while the rest of your site is statically-generated.
If your project used hybrid rendering, you must now remove the output: 'hybrid' option from your Astro config as it no longer exists. However, no other changes to your project are required, and you should have no breaking changes. The previous 'hybrid' behavior is now the default, under a new name 'static'.
If you were using the output: 'static' (default) option, you can continue to use it as before. By default, all of your pages will continue to be prerendered and you will have a completely static site. You should have no breaking changes to your project.
import { defineConfig } from "astro/config";
export default defineConfig({
output: 'hybrid',
});
An adapter is still required to deploy an Astro project with any server-rendered pages. Failure to include an adapter will result in a warning in development and an error at build time.
#117887c0ccfc Thanks @ematipico! - Updates the default value of security.checkOrigin to true, which enables Cross-Site Request Forgery (CSRF) protection by default for pages rendered on demand.
If you had previously configured security.checkOrigin: true, you no longer need this set in your Astro config. This is now the default and it is safe to remove.
To disable this behavior and opt out of automatically checking that the “origin” header matches the URL sent by each request, you must explicitly set security.checkOrigin: false:
export default defineConfig({
security: {
checkOrigin: false
}
})
#11825560ef15 Thanks @bluwy! - Updates internal Shiki rehype plugin to highlight code blocks as hast (using Shiki’s codeToHast() API). This allows a more direct Markdown and MDX processing, and improves the performance when building the project, but may cause issues with existing Shiki transformers.
If you are using Shiki transformers passed to markdown.shikiConfig.transformers, you must make sure they do not use the postprocess hook as it no longer runs on code blocks in .md and .mdx files. (See the Shiki documentation on transformer hooks for more information).
Code blocks in .mdoc files and <Code /> component do not use the internal Shiki rehype plugin and are unaffected.
#122684e9a3ac Thanks @ematipico! - The command astro add vercel now updates the configuration file differently, and adds @astrojs/vercel as module to import.
This is a breaking change because it requires the version 8.* of @astrojs/vercel.
#117416617491 Thanks @bluwy! - Removes internal JSX handling and moves the responsibility to the @astrojs/mdx package directly. The following exports are also now removed:
astro/jsx/babel.js
astro/jsx/component.js
astro/jsx/index.js
astro/jsx/renderer.js
astro/jsx/server.js
astro/jsx/transform-options.js
If your project includes .mdx files, you must upgrade @astrojs/mdx to the latest version so that it doesn’t rely on these entrypoints to handle your JSX.
#117829a2aaa0 Thanks @Princesseuh! - Makes the compiledContent property of Markdown content an async function, this change should fix underlying issues where sometimes when using a custom image service and images inside Markdown, Node would exit suddenly without any error message.
---
import * as myPost from "../post.md";
const content = myPost.compiledContent();
const content = await myPost.compiledContent();
---
<Fragment set:html={content} />
#118192bdde80 Thanks @bluwy! - Updates the Astro config loading flow to ignore processing locally-linked dependencies with Vite (e.g. npm link, in a monorepo, etc). Instead, they will be normally imported by the Node.js runtime the same way as other dependencies from node_modules.
Previously, Astro would process locally-linked dependencies which were able to use Vite features like TypeScript when imported by the Astro config file.
However, this caused confusion as integration authors may test against a package that worked locally, but not when published. This method also restricts using CJS-only dependencies because Vite requires the code to be ESM. Therefore, Astro’s behaviour is now changed to ignore processing any type of dependencies by Vite.
In most cases, make sure your locally-linked dependencies are built to JS before running the Astro project, and the config loading should work as before.
Usage of astro:content in the client has always been discouraged because it leads to all of your content winding up in your client bundle, and can possibly leaks secrets.
This formally makes doing so impossible, adding to the previous warning with errors.
In the future Astro might add APIs for client-usage based on needs.
#11979423dfc1 Thanks @bluwy! - Bumps vite dependency to v6.0.0-beta.2. The version is pinned and will be updated as new Vite versions publish to prevent unhandled breaking changes. For the full list of Vite-specific changes, see its changelog.
#118593804711 Thanks @florian-lefebvre! - Changes the default tsconfig.json with better defaults, and makes src/env.d.ts optional
Astro’s default tsconfig.json in starter examples has been updated to include generated types and exclude your build output. This means that src/env.d.ts is only necessary if you have added custom type declarations or if you’re not using a tsconfig.json file.
Additionally, running astro sync no longer creates, nor updates, src/env.d.ts as it is not required for type-checking standard Astro projects.
To update your project to Astro’s recommended TypeScript settings, please add the following include and exclude properties to tsconfig.json:
{
"extends": "astro/tsconfigs/base",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}
#11715d74617c Thanks @Princesseuh! - Refactor the exported types from the astro module. There should normally be no breaking changes, but if you relied on some previously deprecated types, these might now have been fully removed.
In most cases, updating your code to move away from previously deprecated APIs in previous versions of Astro should be enough to fix any issues.
#12551abf9a89 Thanks @ematipico! - Refactors legacy content and data collections to use the Content Layer API glob() loader for better performance and to support backwards compatibility. Also introduces the legacy.collections flag for projects that are unable to update to the new behavior immediately.
:warning: BREAKING CHANGE FOR LEGACY CONTENT COLLECTIONS :warning:
By default, collections that use the old types (content or data) and do not define a loader are now implemented under the hood using the Content Layer API’s built-in glob() loader, with extra backward-compatibility handling.
In order to achieve backwards compatibility with existing content collections, the following have been implemented:
a glob loader collection is defined, with patterns that match the previous handling (matches src/content/<collection name>/**/*.md and other content extensions depending on installed integrations, with underscore-prefixed files and folders ignored)
When used in the runtime, the entries have an ID based on the filename in the same format as legacy collections
A slug field is added with the same format as before
A render() method is added to the entry, so they can be called using entry.render()
getEntryBySlug is supported
In order to achieve backwards compatibility with existing data collections, the following have been implemented:
a glob loader collection is defined, with patterns that match the previous handling (matches src/content/<collection name>/**/*{.json,.yaml} and other data extensions, with underscore-prefixed files and folders ignored)
Entries have an ID that is not slugified
getDataEntryById is supported
While this backwards compatibility implementation is able to emulate most of the features of legacy collections, there are some differences and limitations that may cause breaking changes to existing collections:
In previous versions of Astro, collections would be generated for all folders in src/content/, even if they were not defined in src/content/config.ts. This behavior is now deprecated, and collections should always be defined in src/content/config.ts. For existing collections, these can just be empty declarations (e.g. const blog = defineCollection({})) and Astro will implicitly define your legacy collection for you in a way that is compatible with the new loading behavior.
The special layout field is not supported in Markdown collection entries. This property is intended only for standalone page files located in src/pages/ and not likely to be in your collection entries. However, if you were using this property, you must now create dynamic routes that include your page styling.
Sort order of generated collections is non-deterministic and platform-dependent. This means that if you are calling getCollection(), the order in which entries are returned may be different than before. If you need a specific order, you should sort the collection entries yourself.
image().refine() is not supported. If you need to validate the properties of an image you will need to do this at runtime in your page or component.
the key argument of getEntry(collection, key) is typed as string, rather than having types for every entry.
A new legacy configuration flag legacy.collections is added for users that want to keep their current legacy (content and data) collections behavior (available in Astro v2 - v4), or who are not yet ready to update their projects:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
legacy: {
collections: true,
},
});
When set, no changes to your existing collections are necessary, and the restrictions on storing both new and old collections continue to exist: legacy collections (only) must continue to remain in src/content/, while new collections using a loader from the Content Layer API are forbidden in that folder.
Previously, non-boolean attributes may not have included their values when rendered to HTML. In Astro v5.0, the values are now explicitly rendered as ="true" or ="false"
In the following .astro examples, only allowfullscreen is a boolean attribute:
<!-- src/pages/index.astro --><!-- `allowfullscreen` is a boolean attribute -->
<pallowfullscreen={true}></p>
<pallowfullscreen={false}></p>
<!-- `inherit` is *not* a boolean attribute -->
<pinherit={true}></p>
<pinherit={false}></p>
<!-- `data-*` attributes are not boolean attributes -->
<pdata-light={true}></p>
<pdata-light={false}></p>
Astro v5.0 now preserves the full data attribute with its value when rendering the HTML of non-boolean attributes:
<p allowfullscreen></p>
<p></p>
<p inherit="true"></p>
<p inherit></p>
<p inherit="false"></p>
<p data-light></p>
<p data-light="true"></p>
<p></p>
<p data-light="false"></p>
If you rely on attribute values, for example to locate elements or to conditionally render, update your code to match the new non-boolean attribute values:
el.getAttribute('inherit') === ''
el.getAttribute('inherit') === 'false'
el.hasAttribute('data-light')
el.dataset.light === 'true'
#11770cfa6a47 Thanks @Princesseuh! - Removed support for the Squoosh image service. As the underlying library libsquoosh is no longer maintained, and the image service sees very little usage we have decided to remove it from Astro.
Our recommendation is to use the base Sharp image service, which is more powerful, faster, and more actively maintained.
import { squooshImageService } from "astro/config";
#1223190ae100 Thanks @bluwy! - Updates the automatic charset=utf-8 behavior for Markdown pages, where instead of responding with charset=utf-8 in the Content-Type header, Astro will now automatically add the <meta charset="utf-8"> tag instead.
This behaviour only applies to Markdown pages (.md or similar Markdown files located within src/pages/) that do not use Astro’s special layout frontmatter property. It matches the rendering behaviour of other non-content pages, and retains the minimal boilerplate needed to write with non-ASCII characters when adding individual Markdown pages to your site.
If your Markdown pages use the layout frontmatter property, then HTML encoding will be handled by the designated layout component instead, and the <meta charset="utf-8"> tag will not be added to your page by default.
If you require charset=utf-8 to render your page correctly, make sure that your layout components contain the <meta charset="utf-8"> tag. You may need to add this if you have not already done so.
This change removes support for the functionPerRoute option both in Astro and @astrojs/vercel.
This option made it so that each route got built as separate entrypoints so that they could be loaded as separate functions. The hope was that by doing this it would decrease the size of each function. However in practice routes use most of the same code, and increases in function size limitations made the potential upsides less important.
Additionally there are downsides to functionPerRoute, such as hitting limits on the number of functions per project. The feature also never worked with some Astro features like i18n domains and request rewriting.
Given this, the feature has been removed from Astro.
#11864ee38b3a Thanks @ematipico! - ### [changed]: RouteData.distURL is now an array
In Astro v4.x, RouteData.distURL was undefined or a URL
Astro v5.0, RouteData.distURL is undefined or an array of URL. This was a bug, because a route can generate multiple files on disk, especially when using dynamic routes such as [slug] or [...slug].
What should I do?
Update your code to handle RouteData.distURL as an array.
if (route.distURL) {
if (route.distURL.endsWith('index.html')) {
// do something
}
for (const url of route.distURL) {
if (url.endsWith('index.html')) {
// do something
}
}
}
#112534e5cc5a Thanks @kevinzunigacuellar! - Changes the data returned for page.url.current, page.url.next, page.url.prev, page.url.first and page.url.last to include the value set for base in your Astro config.
Previously, you had to manually prepend your configured value for base to the URL path. Now, Astro automatically includes your base value in next and prev URLs.
If you are using the paginate() function for “previous” and “next” URLs, remove any existing base value as it is now added for you:
---
export async function getStaticPaths({ paginate }) {
const astronautPages = [{
astronaut: 'Neil Armstrong',
}, {
astronaut: 'Buzz Aldrin',
}, {
astronaut: 'Sally Ride',
}, {
astronaut: 'John Glenn',
}];
return paginate(astronautPages, { pageSize: 1 });
}
const { page } = Astro.props;
// `base: /'docs'` configured in `astro.config.mjs`
const prev = "/docs" + page.url.prev;
const prev = page.url.prev;
---
<a id="prev" href={prev}>Back</a>
#120797febf1f Thanks @ematipico! - params passed in getStaticPaths are no longer automatically decoded.
[changed]: params aren’t decoded anymore.
In Astro v4.x, params in were automatically decoded using decodeURIComponent.
Astro v5.0 doesn’t automatically decode params in getStaticPaths anymore, so you’ll need to manually decode them yourself if needed
What should I do?
If you were relying on the automatic decode, you’ll need to manually decode it using decodeURI.
Note that the use of decodeURIComponent) is discouraged for getStaticPaths because it decodes more characters than it should, for example /, ?, # and more.
---
export function getStaticPaths() {
return [
{ params: { id: decodeURI("%5Bpage%5D") } },
{ params: { id: "%5Bpage%5D" } },
]
}
const { id } = Astro.params;
---
🍿 Minor Changes
#11941b6a5f39 Thanks @Princesseuh! - Adapters can now specify the build output type they’re intended for using the adapterFeatures.buildOutput property. This property can be used to always generate a server output, even if the project doesn’t have any server-rendered pages.
If your adapter specifies buildOutput: 'static', and the user’s project contains server-rendered pages, Astro will warn in development and error at build time. Note that a hybrid output, containing both static and server-rendered pages, is considered to be a server output, as a server is required to serve the server-rendered pages.
#12067c48916c Thanks @stramel! - Adds experimental support for built-in SVG components.
This feature allows you to import SVG files directly into your Astro project as components. By default, Astro will inline the SVG content into your HTML output.
To enable this feature, set experimental.svg to true in your Astro config:
{
experimental: {
svg: true,
},
}
To use this feature, import an SVG file in your Astro project, passing any common SVG attributes to the imported component. Astro also provides a size attribute to set equal height and width properties:
---
import Logo from'./path/to/svg/file.svg';
---
<Logosize={24} />
For a complete overview, and to give feedback on this experimental API, see the Feature RFC.
#1222651d13e2 Thanks @ematipico! - The following renderer fields and integration fields now accept URL as a type:
#12243eb41d13 Thanks @florian-lefebvre! - Improves defineConfig type safety. TypeScript will now error if a group of related configuration options do not have consistent types. For example, you will now see an error if your language set for i18n.defaultLocale is not one of the supported locales specified in i18n.locales.
#123298309c61 Thanks @florian-lefebvre! - Adds a new astro:routes:resolved hook to the Integration API. Also update the astro:build:done hook by deprecating routes and adding a new assets map.
When building an integration, you can now get access to routes inside the astro:routes:resolved hook:
constintegration= () => {
return {
name: 'my-integration',
hooks: {
'astro:routes:resolved': ({ routes }) => {
console.log(routes);
},
},
};
};
This hook runs before astro:config:done, and whenever a route changes in development.
The routes array from astro:build:done is now deprecated, and exposed properties are now available on astro:routes:resolved, except for distURL. For this, you can use the newly exposed assets map:
const integration = () => {
let routes
return {
name: 'my-integration',
hooks: {
'astro:routes:resolved': (params) => {
routes = params.routes
},
'astro:build:done': ({
routes
assets
}) => {
for (const route of routes) {
const distURL = assets.get(route.pattern)
if (distURL) {
Object.assign(route, { distURL })
}
}
console.log(routes)
}
}
}
}
#11911c3dce83 Thanks @ascorbic! - The Content Layer API introduced behind a flag in 4.14.0 is now stable and ready for use in Astro v5.0.
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. There are significant improvements to performance with large collections of local files. For more details, see the Content Layer RFC.
If you previously used this feature, you can now remove the experimental.contentLayer flag from your Astro config:
astro.config.mjs
import { defineConfig } from 'astro'
export default defineConfig({
experimental: {
contentLayer: true
}
})
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';
constblog=defineCollection({
// The ID is a slug generated from the path of the file relative to `base`
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:
// 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...
});
exportconstcollections= { countries };
For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading, and gives 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 package that exports a loader and publish it to npm, and then anyone can use it on their site. 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:
The <ViewTransitions /> component has been renamed to <ClientRouter />. There are no other changes than the name. The old name will continue to work in Astro 5.x, but will be removed in 6.0.
This change was done to clarify the role of the component within Astro’s View Transitions support. Astro supports View Transitions APIs in a few different ways, and renaming the component makes it more clear that the features you get from the ClientRouter component are slightly different from what you get using the native CSS-based MPA router.
We still intend to maintain the ClientRouter as before, and it’s still important for use-cases that the native support doesn’t cover, such as persisting state between pages.
#11875a8a3d2c Thanks @florian-lefebvre! - Adds a new property isPrerendered to the globals Astro and APIContext . This boolean value represents whether or not the current page is prerendered:
src/pages/index.astro
---
exportconstprerender=true;
---
src/middleware.js
exportconstonRequest= (ctx, next) => {
console.log(ctx.isPrerendered); // it will log true
returnnext();
};
#1204721b5e80 Thanks @rgodha24! - Adds a new optional parser property to the built-in file() loader for content collections to support additional file types such as toml and csv.
The file() loader now accepts a second argument that defines a parser function. This allows you to specify a custom parser (e.g. toml.parse or csv-parse) to create a collection from a file’s contents. The file() loader will automatically detect and parse JSON and YAML files (based on their file extension) with no need for a parser.
This works with any type of custom file formats including csv and toml. The following example defines a content collection dogs using a .toml file.
[[dogs]]
id = "..."
age = "..."
[[dogs]]
id = "..."
age = "..."
After importing TOML’s parser, you can load the dogs collection into your project by passing both a file path and parser to the file() loader.
The parser argument also allows you to load a single collection from a nested JSON document. For example, this JSON file contains multiple collections:
{ "dogs": [{}], "cats": [{}] }
You can seperate these collections by passing a custom parser to the file() loader like so:
#1169805139ef Thanks @ematipico! - Adds a new property to the globals Astro and APIContext called routePattern. The routePattern represents the current route (component)
that is being rendered by Astro. It’s usually a path pattern will look like this: blog/[slug]:
src/pages/blog/[slug].astro
---
constroute= Astro.routePattern;
console.log(route); // it will log "blog/[slug]"
---
src/pages/index.js
exportconstGET= (ctx) => {
console.log(ctx.routePattern); // it will log src/pages/index.js
returnnew Response.json({ loreum: 'ipsum' });
};
#11941b6a5f39 Thanks @Princesseuh! - Adds a new buildOutput property to the astro:config:done hook returning the build output type.
This can be used to know if the user’s project will be built as a static site (HTML files), or a server-rendered site (whose exact output depends on the adapter).
#12377af867f3 Thanks @ascorbic! - Adds experimental support for automatic responsive images
This feature is experimental and may change in future versions. To enable it, set experimental.responsiveImages to true in your astro.config.mjs file.
astro.config.mjs
{
experimental: {
responsiveImages: true,
},
}
When this flag is enabled, you can pass a layout prop to any <Image /> or <Picture /> component to create a responsive image. When a layout is set, images have automatically generated srcset and sizes attributes based on the image’s dimensions and the layout type. Images with responsive and full-width layouts will have styles applied to ensure they resize according to their container.
---
import { Image, Picture } from'astro:assets';
import myImage from'../assets/my_image.png';
---
<Image
src={myImage}
alt="A description of my image."
layout="responsive"
width={800}
height={600}
/>
<Picture
src={myImage}
alt="A description of my image."
layout="full-width"
formats={['avif', 'webp', 'jpeg']}
/>
This <Image /> component will generate the following HTML output:
These are additional properties available to the <Image /> and <Picture /> components when responsive images are enabled:
layout: The layout type for the image. Can be responsive, fixed, full-width or none. Defaults to value of image.experimentalLayout.
fit: Defines how the image should be cropped if the aspect ratio is changed. Values match those of CSS object-fit. Defaults to cover, or the value of image.experimentalObjectFit if set.
position: Defines the position of the image crop if the aspect ratio is changed. Values match those of CSS object-position. Defaults to center, or the value of image.experimentalObjectPosition if set.
priority: If set, eagerly loads the image. Otherwise images will be lazy-loaded. Use this for your largest above-the-fold image. Defaults to false.
Default responsive image settings
You can enable responsive images for all <Image /> and <Picture /> components by setting image.experimentalLayout with a default value. This can be overridden by the layout prop on each component.
Example:
astro.config.mjs
{
image: {
// Used for all `<Image />` and `<Picture />` components unless overridden
experimentalLayout: 'responsive',
},
experimental: {
responsiveImages: true,
},
}
---
import { Image } from'astro:assets';
import myImage from'../assets/my_image.png';
---
<Imagesrc={myImage} alt="This will use responsive layout"width={800} height={600} />
<Imagesrc={myImage} alt="This will use full-width layout"layout="full-width" />
<Imagesrc={myImage} alt="This will disable responsive images"layout="none" />
For a complete overview, and to give feedback on this experimental API, see the Responsive Images RFC.
#1215093351bc Thanks @bluwy! - Adds support for passing values other than "production" or "development" to the --mode flag (e.g. "staging", "testing", or any custom value) to change the value of import.meta.env.MODE or the loaded .env file. This allows you take advantage of Vite’s mode feature.
Also adds a new --devOutput flag for astro build that will output a development-based build.
Note that changing the mode does not change the kind of code transform handled by Vite and Astro:
In astro dev, Astro will transform code with debug information.
In astro build, Astro will transform code with the most optimized output and removes debug information.
In astro build --devOutput (new flag), Astro will transform code with debug information like in astro dev.
This enables various usecases like:
Terminal window
# Run the dev server connected to a "staging" API
astrodev--modestaging
# Build a site that connects to a "staging" API
astrobuild--modestaging
# Build a site that connects to a "production" API with additional debug information
astrobuild--devOutput
# Build a site that connects to a "testing" API
astrobuild--modetesting
The different modes can be used to load different .env files, e.g. .env.staging or .env.production, which can be customized for each environment, for example with different API_URL environment variable values.
#1251014feaf3 Thanks @bholmesdev! - Changes the generated URL query param from _astroAction to _action when submitting a form using Actions. This avoids leaking the framework name into the URL bar, which may be considered a security issue.
#11806f7f2338 Thanks @Princesseuh! - The value of the different properties on supportedAstroFeatures for adapters can now be objects, with a support and message properties. The content of the message property will be shown in the Astro CLI when the adapter is not compatible with the feature, allowing one to give a better informational message to the user.
This is notably useful with the new limited value, to explain to the user why support is limited.
#1207161d248e Thanks @Princesseuh! - astro add no longer automatically sets output: 'server'. Since the default value of output now allows for server-rendered pages, it no longer makes sense to default to full server builds when you add an adapter
Server islands are Astro’s solution for highly cacheable pages of mixed static and dynamic content. They allow you to specify components that should run on the server, allowing the rest of the page to be more aggressively cached, or even generated statically.
Turn any .astro component into a server island by adding the server:defer directive and optionally, fallback placeholder content. It will be rendered dynamically at runtime outside the context of the rest of the page, allowing you to add longer cache headers for the pages, or even prerender them.
#12373d10f918 Thanks @bholmesdev! - Changes the default behavior for Astro Action form requests to a standard POST submission.
In Astro 4.x, actions called from an HTML form would trigger a redirect with the result forwarded using cookies. This caused issues for large form errors and return values that exceeded the 4 KB limit of cookie-based storage.
Astro 5.0 now renders the result of an action as a POST result without any forwarding. This will introduce a “confirm form resubmission?” dialog when a user attempts to refresh the page, though it no longer imposes a 4 KB limit on action return value.
We recommend using a session storage provider as described in our Netlify Blob example. However, if you prefer the cookie forwarding behavior from 4.X and accept the 4 KB size limit, you can implement the pattern as shown in this sample snippet:
thrownewError('Internal: Referer unexpectedly missing from Action POST request.');
}
return context.redirect(referer);
}
// Redirect to the destination page on success
return context.redirect(context.originPathname);
}
returnnext();
});
#124753f02d5f Thanks @ascorbic! - Changes the default content config location from src/content/config.* to src/content.config.*.
The previous location is still supported, and is required if the legacy.collections flag is enabled.
#119630a1036e Thanks @florian-lefebvre! - Adds a new createCodegenDir() function to the astro:config:setup hook in the Integrations API
In 4.14, we introduced the injectTypes utility on the astro:config:done hook. It can create .d.ts files and make their types available to user’s projects automatically. Under the hood, it creates a file in <root>/.astro/integrations/<normalized_integration_name>.
While the .astro directory has always been the preferred place to write code generated files, it has also been prone to mistakes. For example, you can write a .astro/types.d.ts file, breaking Astro types. Or you can create a file that overrides a file created by another integration.
In this release, <root>/.astro/integrations/<normalized_integration_name> can now be retrieved in the astro:config:setup hook by calling createCodegenDir(). It allows you to have a dedicated folder, avoiding conflicts with another integration or Astro itself. This directory is created by calling this function so it’s safe to write files to it directly:
#1237994f4fe8 Thanks @Princesseuh! - Adds a new components exported from astro/components: Welcome, to be used by the new Basics template
#11806f7f2338 Thanks @Princesseuh! - Adds a new limited value for the different properties of supportedAstroFeatures for adapters, which indicates that the adapter is compatible with the feature, but with some limitations. This is useful for adapters that support a feature, but not in all cases or with all options.
When importing astro/config, types from astro/client will be made automatically available to your project. If your project tsconfig.json changes how references behave, you’ll still have access to these types after running astro sync.
Astro Content Layer API independently solves some of the caching and performance issues with legacy content collections that this strategy attempted to address. This feature has been replaced with continued work on improvements to the content layer. If you were using this experimental feature, you must now remove the flag from your Astro config as it no longer exists:
export default defineConfig({
experimental: {
contentCollectionsCache: true
}
})
The cacheManifest boolean argument is no longer passed to the astro:build:done integration hook:
const integration = {
name: "my-integration",
hooks: {
"astro:build:done": ({
cacheManifest,
logger
}) => {}
}
}
🐞 Patch Changes
#1256597f413f Thanks @ascorbic! - Fixes a bug where content types were not generated when first running astro dev unless src/content exists
The signature for app.render() has changed, and the second argument is now an options object called renderOptions with more options for customizing rendering.
The renderOptions are:
addCookieHeader: Determines whether Astro will set the Set-Cookie header, otherwise the adapter is expected to do so itself.
clientAddress: The client IP address used to set Astro.clientAddress.
locals: An object of locals that’s set to Astro.locals.
routeData: An object specifying the route to use.
#1252233b0e30 Thanks @ascorbic! - Fixes a bug where content config was ignored if it was outside of content dir and has a parent dir with an underscore
#124244364bff Thanks @ematipico! - Fixes an issue where an incorrect usage of Astro actions was lost when porting the fix from v4 to v5
#12438c8f877c Thanks @ascorbic! - Fixes a bug where legacy content types were generated for content layer collections if they were in the content directory
#119604410130 Thanks @ascorbic! - Fixes an issue where the refresh context data was not passed correctly to content layer loaders
#11878334948c Thanks @ascorbic! - Adds a new function refreshContent to the astro:server:setup hook that allows integrations to refresh the content layer. This can be used, for example, to register a webhook endpoint during dev, or to open a socket to a CMS to listen for changes.
By default, refreshContent will refresh all collections. You can optionally pass a loaders property, which is an array of loader names. If provided, only collections that use those loaders will be refreshed. For example, A CMS integration could use this property to only refresh its own collections.
You can also pass a context object to the loaders. This can be used to pass arbitrary data, such as the webhook body, or an event from the websocket.
#1257807b9ca8 Thanks @WesSouza! - Explicitly import index.ts to fix types when moduleResolution is NodeNext
#117919393243 Thanks @bluwy! - Updates Astro’s default <script> rendering strategy and removes the experimental.directRenderScript option as this is now the default behavior: scripts are always rendered directly. This new strategy prevents scripts from being executed in pages where they are not used.
Scripts will directly render as declared in Astro files (including existing features like TypeScript, importing node_modules, and deduplicating scripts). You can also now conditionally render scripts in your Astro file.
However, this means scripts are no longer hoisted to the <head>, multiple scripts on a page are no longer bundled together, and the <script> tag may interfere with the CSS styling.
As this is a potentially breaking change to your script behavior, please review your <script> tags and ensure that they behave as expected.
#12011cfdaab2 Thanks @ArmandPhilippot! - Fixes a type and an example in documenting the security.checkOrigin property of Astro config.
Server Island requests include the props used to render the island as well as any slots passed in (excluding the fallback slot). Since browsers have a max 4mb URL length we default to using a POST request to avoid overflowing this length.
However in reality most usage of Server Islands are fairly isolated and won’t exceed this limit, so a GET request is possible by passing this same information via search parameters.
Using GET means we can also include a <link rel="preload"> tag to speed up the request.
This change implements this, with safe fallback to POST.
#1195250a0146 Thanks @ascorbic! - Adds support for array patterns in the built-in glob() content collections loader
The glob loader can now accept an array of multiple patterns as well as string patterns. This allows you to more easily combine multiple patterns into a single collection, and also means you can use negative matches to exclude files from the collection.
constprobes=defineCollection({
// Load all markdown files in the space-probes directory, except for those that start with "voyager-"
#12022ddc3a08 Thanks @Princesseuh! - Properly handle including trailing slash on the image endpoint route based on the trailingSlash config
#1216915fa9ba Thanks @ematipico! - Fixes a bug where configured redirects were incorrectly constructed when reading the file system.
This caused an issue where configuring a redirect in astro.config.mjs like { /old: /new }, failed to trigger the correct redirect in the dev server.
#11914b5d827b Thanks @ascorbic! - Exports types for all LoaderContext properties from astro/loaders to make it easier to use them in custom loaders.
The ScopedDataStore interface (which was previously internal) is renamed to DataStore, to reflect the fact that it’s the only public API for the data store.
#1227025192a0 Thanks @ematipico! - Fixes a bug where the params weren’t correctly computed when rendering URLs with non-English characters
#119275b4e3ab Thanks @florian-lefebvre! - Updates the env configuration reference docs to include a full API reference for envField.
#12591b731b3d Thanks @ascorbic! - Fixes a bug where a catchall route would match an image endpoint request
#12339bdb75a8 Thanks @ematipico! - Adds an error when Astro.rewrite() is used to rewrite an on-demand route with a static route when using the "server" output.
This is a forbidden rewrite because Astro can’t retrieve the emitted static route at runtime. This route is served by the hosting platform, and not Astro itself.
#11943fa4671c Thanks @sarah11918! - Updates error messages that assume content collections are located in src/content/ with more generic language
#1203010a756a Thanks @ascorbic! - Resolves image paths in content layer with initial slash as project-relative
When using the image() schema helper, previously paths with an initial slash were treated as public URLs. This was to match the behavior of markdown images. However this is a change from before, where paths with an initial slash were treated as project-relative. This change restores the previous behavior, so that paths with an initial slash are treated as project-relative.
#1255215f000c Thanks @avanderbergh! - Fixed an issue where modifying the Request.headers prototype during prerendering caused a build error. Removed conflicting value and writable properties from the headers descriptor to prevent Invalid property descriptor errors.
#120709693ad4 Thanks @ematipico! - Fixes an issue where the check origin middleware was incorrectly injected when the build output was "static"
#1216915fa9ba Thanks @ematipico! - Fixes a bug where the dev server was not providing a consistent user experience for configured redirects.
With the fix, when you configure a redirect in astro.config.mjs like this { /old: "/new" }, the dev server return an HTML response that matches the one emitted by a static build.
#1251014feaf3 Thanks @bholmesdev! - Changes the generated URL query param from _astroAction to _action when submitting a form using Actions. This avoids leaking the framework name into the URL bar, which may be considered a security issue.
🐞 Patch Changes
#1252233b0e30 Thanks @ascorbic! - Fixes a bug where content config was ignored if it was outside of content dir and has a parent dir with an underscore
#1247746f6b38 Thanks @ematipico! - Fixes an issue where the SSR build was emitting the dist/server/entry.mjs file with an incorrect import at the top of the file/
#12365a23985b Thanks @apatel369! - Fixes an issue where Astro.currentLocale was not correctly returning the locale for 404 and 500 pages.
#12067c48916c Thanks @stramel! - Adds experimental support for built-in SVG components.
This feature allows you to import SVG files directly into your Astro project as components. By default, Astro will inline the SVG content into your HTML output.
To enable this feature, set experimental.svg to true in your Astro config:
{
experimental: {
svg: true,
},
}
To use this feature, import an SVG file in your Astro project, passing any common SVG attributes to the imported component. Astro also provides a size attribute to set equal height and width properties:
---
import Logo from'./path/to/svg/file.svg';
---
<Logosize={24} />
For a complete overview, and to give feedback on this experimental API, see the Feature RFC.
#123298309c61 Thanks @florian-lefebvre! - Adds a new astro:routes:resolved hook to the Integration API. Also update the astro:build:done hook by deprecating routes and adding a new assets map.
When building an integration, you can now get access to routes inside the astro:routes:resolved hook:
constintegration= () => {
return {
name: 'my-integration',
hooks: {
'astro:routes:resolved': ({ routes }) => {
console.log(routes);
},
},
};
};
This hook runs before astro:config:done, and whenever a route changes in development.
The routes array from astro:build:done is now deprecated, and exposed properties are now available on astro:routes:resolved, except for distURL. For this, you can use the newly exposed assets map:
const integration = () => {
let routes
return {
name: 'my-integration',
hooks: {
'astro:routes:resolved': (params) => {
routes = params.routes
},
'astro:build:done': ({
routes
assets
}) => {
for (const route of routes) {
const distURL = assets.get(route.pattern)
if (distURL) {
Object.assign(route, { distURL })
}
}
console.log(routes)
}
}
}
}
#12377af867f3 Thanks @ascorbic! - Adds experimental support for automatic responsive images
This feature is experimental and may change in future versions. To enable it, set experimental.responsiveImages to true in your astro.config.mjs file.
astro.config.mjs
{
experimental: {
responsiveImages: true,
},
}
When this flag is enabled, you can pass a layout prop to any <Image /> or <Picture /> component to create a responsive image. When a layout is set, images have automatically generated srcset and sizes attributes based on the image’s dimensions and the layout type. Images with responsive and full-width layouts will have styles applied to ensure they resize according to their container.
---
import { Image, Picture } from'astro:assets';
import myImage from'../assets/my_image.png';
---
<Image
src={myImage}
alt="A description of my image."
layout="responsive"
width={800}
height={600}
/>
<Picture
src={myImage}
alt="A description of my image."
layout="full-width"
formats={['avif', 'webp', 'jpeg']}
/>
This <Image /> component will generate the following HTML output:
These are additional properties available to the <Image /> and <Picture /> components when responsive images are enabled:
layout: The layout type for the image. Can be responsive, fixed, full-width or none. Defaults to value of image.experimentalLayout.
fit: Defines how the image should be cropped if the aspect ratio is changed. Values match those of CSS object-fit. Defaults to cover, or the value of image.experimentalObjectFit if set.
position: Defines the position of the image crop if the aspect ratio is changed. Values match those of CSS object-position. Defaults to center, or the value of image.experimentalObjectPosition if set.
priority: If set, eagerly loads the image. Otherwise images will be lazy-loaded. Use this for your largest above-the-fold image. Defaults to false.
Default responsive image settings
You can enable responsive images for all <Image /> and <Picture /> components by setting image.experimentalLayout with a default value. This can be overridden by the layout prop on each component.
Example:
astro.config.mjs
{
image: {
// Used for all `<Image />` and `<Picture />` components unless overridden
experimentalLayout: 'responsive',
},
experimental: {
responsiveImages: true,
},
}
---
import { Image } from'astro:assets';
import myImage from'../assets/my_image.png';
---
<Imagesrc={myImage} alt="This will use responsive layout"width={800} height={600} />
<Imagesrc={myImage} alt="This will use full-width layout"layout="full-width" />
<Imagesrc={myImage} alt="This will disable responsive images"layout="none" />
For a complete overview, and to give feedback on this experimental API, see the Responsive Images RFC.
#124753f02d5f Thanks @ascorbic! - Changes the default content config location from src/content/config.* to src/content.config.*.
The previous location is still supported, and is required if the legacy.collections flag is enabled.
🐞 Patch Changes
#124244364bff Thanks @ematipico! - Fixes an issue where an incorrect usage of Astro actions was lost when porting the fix from v4 to v5
#12438c8f877c Thanks @ascorbic! - Fixes a bug where legacy content types were generated for content layer collections if they were in the content directory
#12436453ec6b Thanks @martrapp! - Fixes a potential null access in the clientside router
#123920462219 Thanks @apatel369! - Fixes an issue where scripts were not correctly injected during the build. The issue was triggered when there were injected routes with the same entrypoint and different pattern
#12373d10f918 Thanks @bholmesdev! - Changes the default behavior for Astro Action form requests to a standard POST submission.
In Astro 4.x, actions called from an HTML form would trigger a redirect with the result forwarded using cookies. This caused issues for large form errors and return values that exceeded the 4 KB limit of cookie-based storage.
Astro 5.0 now renders the result of an action as a POST result without any forwarding. This will introduce a “confirm form resubmission?” dialog when a user attempts to refresh the page, though it no longer imposes a 4 KB limit on action return value.
We recommend using a session storage provider as described in our Netlify Blob example. However, if you prefer the cookie forwarding behavior from 4.X and accept the 4 KB size limit, you can implement the pattern as shown in this sample snippet:
thrownewError('Internal: Referer unexpectedly missing from Action POST request.');
}
return context.redirect(referer);
}
// Redirect to the destination page on success
return context.redirect(context.originPathname);
}
returnnext();
});
🐞 Patch Changes
#12339bdb75a8 Thanks @ematipico! - Adds an error when Astro.rewrite() is used to rewrite an on-demand route with a static route when using the "server" output.
This is a forbidden rewrite because Astro can’t retrieve the emitted static route at runtime. This route is served by the hosting platform, and not Astro itself.
#12402823e73b Thanks @ematipico! - Fixes a case where Astro allowed to call an action without using Astro.callAction. This is now invalid, and Astro will show a proper error.
---
import { actions } from "astro:actions";
const result = actions.getUser({ userId: 123 });
const result = Astro.callAction(actions.getUser, { userId: 123 });
---
#124019cca108 Thanks @bholmesdev! - Fixes unexpected 200 status in dev server logs for action errors and redirects.
#12355c4726d7 Thanks @apatel369! - Improves error reporting for invalid frontmatter in MDX files during the astro build command. The error message now includes the file path where the frontmatter parsing failed.
#122684e9a3ac Thanks @ematipico! - The command astro add vercel now updates the configuration file differently, and adds @astrojs/vercel as module to import.
This is a breaking change because it requires the version 8.* of @astrojs/vercel.
#1223190ae100 Thanks @bluwy! - Updates the automatic charset=utf-8 behavior for Markdown pages, where instead of responding with charset=utf-8 in the Content-Type header, Astro will now automatically add the <meta charset="utf-8"> tag instead.
This behaviour only applies to Markdown pages (.md or similar Markdown files located within src/pages/) that do not use Astro’s special layout frontmatter property. It matches the rendering behaviour of other non-content pages, and retains the minimal boilerplate needed to write with non-ASCII characters when adding individual Markdown pages to your site.
If your Markdown pages use the layout frontmatter property, then HTML encoding will be handled by the designated layout component instead, and the <meta charset="utf-8"> tag will not be added to your page by default.
If you require charset=utf-8 to render your page correctly, make sure that your layout components contain the <meta charset="utf-8"> tag. You may need to add this if you have not already done so.
🍿 Minor Changes
#12243eb41d13 Thanks @florian-lefebvre! - Improves defineConfig type safety. TypeScript will now error if a group of related configuration options do not have consistent types. For example, you will now see an error if your language set for i18n.defaultLocale is not one of the supported locales specified in i18n.locales.
#1215093351bc Thanks @bluwy! - Adds support for passing values other than "production" or "development" to the --mode flag (e.g. "staging", "testing", or any custom value) to change the value of import.meta.env.MODE or the loaded .env file. This allows you take advantage of Vite’s mode feature.
Also adds a new --devOutput flag for astro build that will output a development-based build.
Note that changing the mode does not change the kind of code transform handled by Vite and Astro:
In astro dev, Astro will transform code with debug information.
In astro build, Astro will transform code with the most optimized output and removes debug information.
In astro build --devOutput (new flag), Astro will transform code with debug information like in astro dev.
This enables various usecases like:
Terminal window
# Run the dev server connected to a "staging" API
astrodev--modestaging
# Build a site that connects to a "staging" API
astrobuild--modestaging
# Build a site that connects to a "production" API with additional debug information
astrobuild--devOutput
# Build a site that connects to a "testing" API
astrobuild--modetesting
The different modes can be used to load different .env files, e.g. .env.staging or .env.production, which can be customized for each environment, for example with different API_URL environment variable values.
🐞 Patch Changes
#123027196c24 Thanks @ematipico! - Fixes an issue where the origin check middleware run for prendered pages
#12341c1786d6 Thanks @ematipico! - Fixes and issue where Astro.currentLocale always returned the default locale when consumed inside a server island.
#1227025192a0 Thanks @ematipico! - Fixes a bug where the params weren’t correctly computed when rendering URLs with non-English characters
#123389ca89b3 Thanks @situ2001! - Resets NODE_ENV to ensure install command run in dev mode
#122869d6bcdb Thanks @florian-lefebvre! - Fixes a case where a warning for experimental astro:env support would be shown when using an adapter but not actually using astro:env
Changes the default page rendering behavior of Astro components in containers, and adds a new option partial: false to render full Astro pages as before.
Previously, the Container API was rendering all Astro components as if they were full Astro pages containing <!DOCTYPE html> by default. This was not intended, and now by default, all components will render as page partials: only the contents of the components without a page shell.
To render the component as a full-fledged Astro page, pass a new option called partial: false to renderToString() and renderToResponse():
import { experimental_AstroContainer as AstroContainer } from'astro/container';
import Card from'../src/components/Card.astro';
constcontainer= AstroContainer.create();
await container.renderToString(Card); // the string will not contain `<!DOCTYPE html>`
await container.renderToString(Card, { partial: false }); // the string will contain `<!DOCTYPE html>`
#1216915fa9ba Thanks @ematipico! - Fixes a bug where configured redirects were incorrectly constructed when reading the file system.
This caused an issue where configuring a redirect in astro.config.mjs like { /old: /new }, failed to trigger the correct redirect in the dev server.
#1216915fa9ba Thanks @ematipico! - Fixes a bug where the dev server was not providing a consistent user experience for configured redirects.
With the fix, when you configure a redirect in astro.config.mjs like this { /old: "/new" }, the dev server return an HTML response that matches the one emitted by a static build.
#1222379ffa5d Thanks @ArmandPhilippot! - Fixes a false positive reported by the dev toolbar Audit app where a label was considered missing when associated with a button
The button element can be used with a label (e.g. to create a switch) and should not be reported as an accessibility issue when used as a child of a label.
#12199c351352 Thanks @ematipico! - Fixes a regression in the computation of Astro.currentLocale
#12222fb55695 Thanks @ematipico! - Fixes an issue where the edge middleware couldn’t correctly compute the client IP address when calling ctx.clientAddress()
Using document.scripts is unsafe because if the application has a name="scripts" this will shadow the built-in document.scripts. Fix is to use getElementsByTagName to ensure we’re only grabbing real scripts.
#121732d10de5 Thanks @ematipico! - Fixes a bug where Astro Actions couldn’t redirect to the correct pathname when there was a rewrite involved.
The following example configures Shiki to highlight cjs code blocks using the javascript syntax highlighter:
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
markdown: {
shikiConfig: {
langAlias: {
cjs: 'javascript',
},
},
},
});
Then in your Markdown, you can use the alias as the language for a code block for syntax highlighting:
```cjs
'use strict';
functioncommonJs() {
return'I am a commonjs file';
}
```
#119843ac2263 Thanks @chaegumi! - Adds a new build.concurreny configuration option to specify the number of pages to build in parallel
In most cases, you should not change the default value of 1.
Use this option only when other attempts to reduce the overall rendering time (e.g. batch or cache long running tasks like fetch calls or data access) are not possible or are insufficient.
Use this option only if the refactors are not possible. If the number is set too high, the page rendering may slow down due to insufficient memory resources and because JS is single-threaded.
[!WARNING]
This feature is stable and is not considered experimental. However, this feature is only intended to address difficult performance issues, and breaking changes may occur in a minor release to keep this option as performant as possible.
astro.config.mjs
import { defineConfig } from'astro';
exportdefaultdefineConfig({
build: {
concurrency: 2,
},
});
🐞 Patch Changes
#12160c6fd1df Thanks @louisescher! - Fixes a bug where astro.config.mts and astro.config.cts weren’t reloading the dev server upon modifications.
#12130e96bcae Thanks @thehansys! - Fixes a bug in the parsing of x-forwarded-\*Request headers, where multiple values assigned to those headers were not correctly parsed.
Now, headers like x-forwarded-proto: https,http are correctly parsed.
HTTP/2 doesn’t support status message, so setting this was logging a warning.
#12151bb6d37f Thanks @ematipico! - Fixes an issue where Astro.currentLocale wasn’t incorrectly computed when the defaultLocale belonged to a custom locale path.
#11979423dfc1 Thanks @bluwy! - Bumps vite dependency to v6.0.0-beta.2. The version is pinned and will be updated as new Vite versions publish to prevent unhandled breaking changes. For the full list of Vite-specific changes, see its changelog.
#12100abf9a89 Thanks @astrobot-houston! - Refactors legacy content and data collections to use the Content Layer API glob() loader for better performance and to support backwards compatibility. Also introduces the legacy.collections flag for projects that are unable to update to the new behavior immediately.
:warning: BREAKING CHANGE FOR LEGACY CONTENT COLLECTIONS :warning:
By default, collections that use the old types (content or data) and do not define a loader are now implemented under the hood using the Content Layer API’s built-in glob() loader, with extra backward-compatibility handling.
In order to achieve backwards compatibility with existing content collections, the following have been implemented:
a glob loader collection is defined, with patterns that match the previous handling (matches src/content/<collection name>/**/*.md and other content extensions depending on installed integrations, with underscore-prefixed files and folders ignored)
When used in the runtime, the entries have an ID based on the filename in the same format as legacy collections
A slug field is added with the same format as before
A render() method is added to the entry, so they can be called using entry.render()
getEntryBySlug is supported
In order to achieve backwards compatibility with existing data collections, the following have been implemented:
a glob loader collection is defined, with patterns that match the previous handling (matches src/content/<collection name>/**/*{.json,.yaml} and other data extensions, with underscore-prefixed files and folders ignored)
Entries have an ID that is not slugified
getDataEntryById is supported
While this backwards compatibility implementation is able to emulate most of the features of legacy collections, there are some differences and limitations that may cause breaking changes to existing collections:
In previous versions of Astro, collections would be generated for all folders in src/content/, even if they were not defined in src/content/config.ts. This behavior is now deprecated, and collections should always be defined in src/content/config.ts. For existing collections, these can just be empty declarations (e.g. const blog = defineCollection({})) and Astro will implicitly define your legacy collection for you in a way that is compatible with the new loading behavior.
The special layout field is not supported in Markdown collection entries. This property is intended only for standalone page files located in src/pages/ and not likely to be in your collection entries. However, if you were using this property, you must now create dynamic routes that include your page styling.
Sort order of generated collections is non-deterministic and platform-dependent. This means that if you are calling getCollection(), the order in which entries are returned may be different than before. If you need a specific order, you should sort the collection entries yourself.
image().refine() is not supported. If you need to validate the properties of an image you will need to do this at runtime in your page or component.
the key argument of getEntry(collection, key) is typed as string, rather than having types for every entry.
A new legacy configuration flag legacy.collections is added for users that want to keep their current legacy (content and data) collections behavior (available in Astro v2 - v4), or who are not yet ready to update their projects:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
legacy: {
collections: true,
},
});
When set, no changes to your existing collections are necessary, and the restrictions on storing both new and old collections continue to exist: legacy collections (only) must continue to remain in src/content/, while new collections using a loader from the Content Layer API are forbidden in that folder.
#120797febf1f Thanks @ematipico! - params passed in getStaticPaths are no longer automatically decoded.
[changed]: params aren’t decoded anymore.
In Astro v4.x, params in were automatically decoded using decodeURIComponent.
Astro v5.0 doesn’t automatically decode params in getStaticPaths anymore, so you’ll need to manually decode them yourself if needed
What should I do?
If you were relying on the automatic decode, you’ll need to manually decode it using decodeURI.
Note that the use of decodeURIComponent) is discouraged for getStaticPaths because it decodes more characters than it should, for example /, ?, # and more.
---
export function getStaticPaths() {
return [
{ params: { id: decodeURI("%5Bpage%5D") } },
{ params: { id: "%5Bpage%5D" } },
]
}
const { id } = Astro.params;
---
🐞 Patch Changes
#1212755e9cd8 Thanks @ascorbic! - Prevents Vite emitting an error when restarting itself
#1210542037f3 Thanks @ascorbic! - Returns custom statusText that has been set in a Response
#12109ea22558 Thanks @ematipico! - Fixes a regression that was introduced by an internal refactor of how the middleware is loaded by the Astro application. The regression was introduced by #11550.
When the edge middleware feature is opted in, Astro removes the middleware function from the SSR manifest, and this wasn’t taken into account during the refactor.
#12106d3a74da Thanks @ascorbic! - Handles case where an immutable Response object is returned from an endpoint
#12090d49a537 Thanks @markjaquith! - Server islands: changes the server island HTML placeholder comment so that it is much less likely to get removed by HTML minifiers.
#1204721b5e80 Thanks @rgodha24! - Adds a new optional parser property to the built-in file() loader for content collections to support additional file types such as toml and csv.
The file() loader now accepts a second argument that defines a parser function. This allows you to specify a custom parser (e.g. toml.parse or csv-parse) to create a collection from a file’s contents. The file() loader will automatically detect and parse JSON and YAML files (based on their file extension) with no need for a parser.
This works with any type of custom file formats including csv and toml. The following example defines a content collection dogs using a .toml file.
[[dogs]]
id = "..."
age = "..."
[[dogs]]
id = "..."
age = "..."
After importing TOML’s parser, you can load the dogs collection into your project by passing both a file path and parser to the file() loader.
The parser argument also allows you to load a single collection from a nested JSON document. For example, this JSON file contains multiple collections:
{ "dogs": [{}], "cats": [{}] }
You can seperate these collections by passing a custom parser to the file() loader like so:
#1207161d248e Thanks @Princesseuh! - astro add no longer automatically sets output: 'server'. Since the default value of output now allows for server-rendered pages, it no longer makes sense to default to full server builds when you add an adapter
#119630a1036e Thanks @florian-lefebvre! - Adds a new createCodegenDir() function to the astro:config:setup hook in the Integrations API
In 4.14, we introduced the injectTypes utility on the astro:config:done hook. It can create .d.ts files and make their types available to user’s projects automatically. Under the hood, it creates a file in <root>/.astro/integrations/<normalized_integration_name>.
While the .astro directory has always been the preferred place to write code generated files, it has also been prone to mistakes. For example, you can write a .astro/types.d.ts file, breaking Astro types. Or you can create a file that overrides a file created by another integration.
In this release, <root>/.astro/integrations/<normalized_integration_name> can now be retrieved in the astro:config:setup hook by calling createCodegenDir(). It allows you to have a dedicated folder, avoiding conflicts with another integration or Astro itself. This directory is created by calling this function so it’s safe to write files to it directly:
Astro Content Layer API independently solves some of the caching and performance issues with legacy content collections that this strategy attempted to address. This feature has been replaced with continued work on improvements to the content layer. If you were using this experimental feature, you must now remove the flag from your Astro config as it no longer exists:
export default defineConfig({
experimental: {
contentCollectionsCache: true
}
})
The cacheManifest boolean argument is no longer passed to the astro:build:done integration hook:
#1203010a756a Thanks @ascorbic! - Resolves image paths in content layer with initial slash as project-relative
When using the image() schema helper, previously paths with an initial slash were treated as public URLs. This was to match the behavior of markdown images. However this is a change from before, where paths with an initial slash were treated as project-relative. This change restores the previous behavior, so that paths with an initial slash are treated as project-relative.
#120345b3ddfa Thanks @ematipico! - Fixes an issue where the middleware wasn’t called when a project uses 404.astro.
#12042243ecb6 Thanks @ematipico! - Fixes a problem in the Container API, where a polyfill wasn’t correctly applied. This caused an issue in some environments where crypto isn’t supported.
#1203826ea5e8 Thanks @ascorbic! - Resolves image paths in content layer with initial slash as project-relative
When using the image() schema helper, previously paths with an initial slash were treated as public URLs. This was to match the behavior of markdown images. However this is a change from before, where paths with an initial slash were treated as project-relative. This change restores the previous behavior, so that paths with an initial slash are treated as project-relative.
#120085608338 Thanks @Princesseuh! - Welcome to the Astro 5 beta! This release has no changes from the latest alpha of this package, but it does bring us one step closer to the final, stable release.
Starting from this release, no breaking changes will be introduced unless absolutely necessary.
#11982d84e444 Thanks @Princesseuh! - Adds a default exclude and include value to the tsconfig presets. {projectDir}/dist is now excluded by default, and {projectDir}/.astro/types.d.ts and {projectDir}/**/* are included by default.
Both of these options can be overridden by setting your own values to the corresponding settings in your tsconfig.json file.
Middleware, API endpoints, and pages can no longer override the locals object in its entirety. You can still append values onto the object, but you can not replace the entire object and delete its existing values.
If you were previously overwriting like so:
ctx.locals = {
one: 1,
two: 2,
};
This can be changed to an assignment on the existing object instead:
The <ViewTransitions /> component has been renamed to <ClientRouter />. There are no other changes than the name. The old name will continue to work in Astro 5.x, but will be removed in 6.0.
This change was done to clarify the role of the component within Astro’s View Transitions support. Astro supports View Transitions APIs in a few different ways, and renaming the component makes it more clear that the features you get from the ClientRouter component are slightly different from what you get using the native CSS-based MPA router.
We still intend to maintain the ClientRouter as before, and it’s still important for use-cases that the native support doesn’t cover, such as persisting state between pages.
The signature for app.render() has changed, and the second argument is now an options object called renderOptions with more options for customizing rendering.
The renderOptions are:
addCookieHeader: Determines whether Astro will set the Set-Cookie header, otherwise the adapter is expected to do so itself.
clientAddress: The client IP address used to set Astro.clientAddress.
locals: An object of locals that’s set to Astro.locals.
#11864ee38b3a Thanks @ematipico! - ### [changed]: entryPoint type inside the hook astro:build:ssr
In Astro v4.x, the entryPoint type was RouteData.
Astro v5.0 the entryPoint type is IntegrationRouteData, which contains a subset of the RouteData type. The fields isIndex and fallbackRoutes were removed.
What should I do?
Update your adapter to change the type of entryPoint from RouteData to IntegrationRouteData.
import type {RouteData} from 'astro';
import type {IntegrationRouteData} from "astro"
function useRoute(route: RouteData) {
function useRoute(route: IntegrationRouteData) {
}
#11908518433e Thanks @Princesseuh! - The image.endpoint config now allow customizing the route of the image endpoint in addition to the entrypoint. This can be useful in niche situations where the default route /_image conflicts with an existing route or your local server setup.
import { defineConfig } from'astro/config';
defineConfig({
image: {
endpoint: {
route: '/image',
entrypoint: './src/image_endpoint.ts',
},
},
});
#11806f7f2338 Thanks @Princesseuh! - Removes the assets property on supportedAstroFeatures for adapters, as it did not reflect reality properly in many cases.
Now, relating to assets, only a single sharpImageService property is available, determining if the adapter is compatible with the built-in sharp image service.
#11864ee38b3a Thanks @ematipico! - ### [changed]: routes type inside the hook astro:build:done
In Astro v4.x, the routes type was RouteData.
Astro v5.0 the routes type is IntegrationRouteData, which contains a subset of the RouteData type. The fields isIndex and fallbackRoutes were removed.
What should I do?
Update your adapter to change the type of routes from RouteData to IntegrationRouteData.
import type {RouteData} from 'astro';
import type {IntegrationRouteData} from "astro"
function useRoute(route: RouteData) {
function useRoute(route: IntegrationRouteData) {
}
#11864ee38b3a Thanks @ematipico! - ### [changed]: RouteData.distURL is now an array
In Astro v4.x, RouteData.distURL was undefined or a URL
Astro v5.0, RouteData.distURL is undefined or an array of URL. This was a bug, because a route can generate multiple files on disk, especially when using dynamic routes such as [slug] or [...slug].
What should I do?
Update your code to handle RouteData.distURL as an array.
if (route.distURL) {
if (route.distURL.endsWith('index.html')) {
// do something
}
for (const url of route.distURL) {
if (url.endsWith('index.html')) {
// do something
}
}
}
🍿 Minor Changes
#11806f7f2338 Thanks @Princesseuh! - The value of the different properties on supportedAstroFeatures for adapters can now be objects, with a support and message properties. The content of the message property will be shown in the Astro CLI when the adapter is not compatible with the feature, allowing one to give a better informational message to the user.
This is notably useful with the new limited value, to explain to the user why support is limited.
Server islands are Astro’s solution for highly cacheable pages of mixed static and dynamic content. They allow you to specify components that should run on the server, allowing the rest of the page to be more aggressively cached, or even generated statically.
Turn any .astro component into a server island by adding the server:defer directive and optionally, fallback placeholder content. It will be rendered dynamically at runtime outside the context of the rest of the page, allowing you to add longer cache headers for the pages, or even prerender them.
#11806f7f2338 Thanks @Princesseuh! - Adds a new limited value for the different properties of supportedAstroFeatures for adapters, which indicates that the adapter is compatible with the feature, but with some limitations. This is useful for adapters that support a feature, but not in all cases or with all options.
When importing astro/config, types from astro/client will be made automatically available to your project. If your project tsconfig.json changes how references behave, you’ll still have access to these types after running astro sync.
#119397b09c62 Thanks @bholmesdev! - Adds support for Zod discriminated unions on Action form inputs. This allows forms with different inputs to be submitted to the same action, using a given input to decide which object should be used for validation.
This example accepts either a create or update form submission, and uses the type field to determine which object to validate against.
#119397b09c62 Thanks @bholmesdev! - Adds support for Zod discriminated unions on Action form inputs. This allows forms with different inputs to be submitted to the same action, using a given input to decide which object should be used for validation.
This example accepts either a create or update form submission, and uses the type field to determine which object to validate against.
#11941b6a5f39 Thanks @Princesseuh! - Merges the output: 'hybrid' and output: 'static' configurations into one single configuration (now called 'static') that works the same way as the previous hybrid option.
It is no longer necessary to specify output: 'hybrid' in your Astro config to use server-rendered pages. The new output: 'static' has this capability included. Astro will now automatically provide the ability to opt out of prerendering in your static site with no change to your output configuration required. Any page route or endpoint can include export const prerender = false to be server-rendered, while the rest of your site is statically-generated.
If your project used hybrid rendering, you must now remove the output: 'hybrid' option from your Astro config as it no longer exists. However, no other changes to your project are required, and you should have no breaking changes. The previous 'hybrid' behavior is now the default, under a new name 'static'.
If you were using the output: 'static' (default) option, you can continue to use it as before. By default, all of your pages will continue to be prerendered and you will have a completely static site. You should have no breaking changes to your project.
import { defineConfig } from "astro/config";
export default defineConfig({
output: 'hybrid',
});
An adapter is still required to deploy an Astro project with any server-rendered pages. Failure to include an adapter will result in a warning in development and an error at build time.
🍿 Minor Changes
#11941b6a5f39 Thanks @Princesseuh! - Adapters can now specify the build output type they’re intended for using the adapterFeatures.buildOutput property. This property can be used to always generate a server output, even if the project doesn’t have any server-rendered pages.
If your adapter specifies buildOutput: 'static', and the user’s project contains server-rendered pages, Astro will warn in development and error at build time. Note that a hybrid output, containing both static and server-rendered pages, is considered to be a server output, as a server is required to serve the server-rendered pages.
#11941b6a5f39 Thanks @Princesseuh! - Adds a new buildOutput property to the astro:config:done hook returning the build output type.
This can be used to know if the user’s project will be built as a static site (HTML files), or a server-rendered site (whose exact output depends on the adapter).
🐞 Patch Changes
#119604410130 Thanks @ascorbic! - Fixes an issue where the refresh context data was not passed correctly to content layer loaders
#1195250a0146 Thanks @ascorbic! - Adds support for array patterns in the built-in glob() content collections loader
The glob loader can now accept an array of multiple patterns as well as string patterns. This allows you to more easily combine multiple patterns into a single collection, and also means you can use negative matches to exclude files from the collection.
constprobes=defineCollection({
// Load all markdown files in the space-probes directory, except for those that start with "voyager-"
#1191646ea29f Thanks @bluwy! - Updates how the build.client and build.server option values get resolved to match existing documentation. With this fix, the option values will now correctly resolve relative to the outDir option. So if outDir is set to ./dist/nested/, then by default:
build.client will resolve to <root>/dist/nested/client/
build.server will resolve to <root>/dist/nested/server/
Previously the values were incorrectly resolved:
build.client was resolved to <root>/dist/nested/dist/client/
build.server was resolved to <root>/dist/nested/dist/server/
If you were relying on the previous build paths, make sure that your project code is updated to the new build paths.
🍿 Minor Changes
#11875a8a3d2c Thanks @florian-lefebvre! - Adds a new property isPrerendered to the globals Astro and APIContext . This boolean value represents whether or not the current page is prerendered:
src/pages/index.astro
---
exportconstprerender=true;
---
src/middleware.js
exportconstonRequest= (ctx, next) => {
console.log(ctx.isPrerendered); // it will log true
returnnext();
};
🐞 Patch Changes
#119275b4e3ab Thanks @florian-lefebvre! - Updates the env configuration reference docs to include a full API reference for envField.
#11943fa4671c Thanks @sarah11918! - Updates error messages that assume content collections are located in src/content/ with more generic language
For Server islands Astro creates a cryptography key in order to hash props for the islands, preventing accidental leakage of secrets.
If you deploy to an environment with rolling updates then there could be multiple instances of your app with different keys, causing potential key mismatches.
To fix this you can now pass the ASTRO_KEY environment variable to your build in order to reuse the same key.
To generate a key use:
astro create-key
This will print out an environment variable to set like:
#118593804711 Thanks @florian-lefebvre! - Changes the default tsconfig.json with better defaults, and makes src/env.d.ts optional
Astro’s default tsconfig.json in starter examples has been updated to include generated types and exclude your build output. This means that src/env.d.ts is only necessary if you have added custom type declarations or if you’re not using a tsconfig.json file.
Additionally, running astro sync no longer creates, nor updates, src/env.d.ts as it is not required for type-checking standard Astro projects.
To update your project to Astro’s recommended TypeScript settings, please add the following include and exclude properties to tsconfig.json:
{
"extends": "astro/tsconfigs/base",
"include": ["**/*", ".astro/types.d.ts"],
"exclude": ["dist"]
}
🍿 Minor Changes
#11911c3dce83 Thanks @ascorbic! - The Content Layer API introduced behind a flag in 4.14.0 is now stable and ready for use in Astro v5.0.
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. There are significant improvements to performance with large collections of local files. For more details, see the Content Layer RFC.
If you previously used this feature, you can now remove the experimental.contentLayer flag from your Astro config:
astro.config.mjs
import { defineConfig } from 'astro'
export default defineConfig({
experimental: {
contentLayer: true
}
})
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';
constblog=defineCollection({
// The ID is a slug generated from the path of the file relative to `base`
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:
// 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...
});
exportconstcollections= { countries };
For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading, and gives 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 package that exports a loader and publish it to npm, and then anyone can use it on their site. 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:
#11902d63bc50 Thanks @ascorbic! - Fixes case where content layer did not update during clean dev builds on Linux and Windows
#11914b5d827b Thanks @ascorbic! - Exports types for all LoaderContext properties from astro/loaders to make it easier to use them in custom loaders.
The ScopedDataStore interface (which was previously internal) is renamed to DataStore, to reflect the fact that it’s the only public API for the data store.
#118613ab3b4e Thanks @bluwy! - Cleans up Astro-specfic metadata attached to vfile.data in Remark and Rehype plugins. Previously, the metadata was attached in different locations with inconsistent names. The metadata is now renamed as below:
The types of imagePaths has also been updated from Set<string> to string[]. The vfile.data.astro.frontmatter metadata is left unchanged.
While we don’t consider these APIs public, they can be accessed by Remark and Rehype plugins that want to re-use Astro’s metadata. If you are using these APIs, make sure to access them in the new locations.
#11825560ef15 Thanks @bluwy! - Updates internal Shiki rehype plugin to highlight code blocks as hast (using Shiki’s codeToHast() API). This allows a more direct Markdown and MDX processing, and improves the performance when building the project, but may cause issues with existing Shiki transformers.
If you are using Shiki transformers passed to markdown.shikiConfig.transformers, you must make sure they do not use the postprocess hook as it no longer runs on code blocks in .md and .mdx files. (See the Shiki documentation on transformer hooks for more information).
Code blocks in .mdoc files and <Code /> component do not use the internal Shiki rehype plugin and are unaffected.
#118192bdde80 Thanks @bluwy! - Updates the Astro config loading flow to ignore processing locally-linked dependencies with Vite (e.g. npm link, in a monorepo, etc). Instead, they will be normally imported by the Node.js runtime the same way as other dependencies from node_modules.
Previously, Astro would process locally-linked dependencies which were able to use Vite features like TypeScript when imported by the Astro config file.
However, this caused confusion as integration authors may test against a package that worked locally, but not when published. This method also restricts using CJS-only dependencies because Vite requires the code to be ESM. Therefore, Astro’s behaviour is now changed to ignore processing any type of dependencies by Vite.
In most cases, make sure your locally-linked dependencies are built to JS before running the Astro project, and the config loading should work as before.
🐞 Patch Changes
#11878334948c Thanks @ascorbic! - Adds a new function refreshContent to the astro:server:setup hook that allows integrations to refresh the content layer. This can be used, for example, to register a webhook endpoint during dev, or to open a socket to a CMS to listen for changes.
By default, refreshContent will refresh all collections. You can optionally pass a loaders property, which is an array of loader names. If provided, only collections that use those loaders will be refreshed. For example, A CMS integration could use this property to only refresh its own collections.
You can also pass a context object to the loaders. This can be used to pass arbitrary data, such as the webhook body, or an event from the websocket.
Usage of astro:content in the client has always been discouraged because it leads to all of your content winding up in your client bundle, and can possibly leaks secrets.
This formally makes doing so impossible, adding to the previous warning with errors.
In the future Astro might add APIs for client-usage based on needs.
#112534e5cc5a Thanks @kevinzunigacuellar! - Changes the data returned for page.url.current, page.url.next, page.url.prev, page.url.first and page.url.last to include the value set for base in your Astro config.
Previously, you had to manually prepend your configured value for base to the URL path. Now, Astro automatically includes your base value in next and prev URLs.
If you are using the paginate() function for “previous” and “next” URLs, remove any existing base value as it is now added for you:
---
export async function getStaticPaths({ paginate }) {
const astronautPages = [{
astronaut: 'Neil Armstrong',
}, {
astronaut: 'Buzz Aldrin',
}, {
astronaut: 'Sally Ride',
}, {
astronaut: 'John Glenn',
}];
return paginate(astronautPages, { pageSize: 1 });
}
const { page } = Astro.props;
// `base: /'docs'` configured in `astro.config.mjs`
const prev = "/docs" + page.url.prev;
const prev = page.url.prev;
---
<a id="prev" href={prev}>Back</a>
🍿 Minor Changes
#1169805139ef Thanks @ematipico! - Adds a new property to the globals Astro and APIContext called routePattern. The routePattern represents the current route (component)
that is being rendered by Astro. It’s usually a path pattern will look like this: blog/[slug]:
src/pages/blog/[slug].astro
---
const route = Astro.routePattern;
console.log(route); // it will log "blog/[slug]"
---
src/pages/index.js
exportconstGET= (ctx) => {
console.log(ctx.routePattern); // it will log src/pages/index.js
returnnew Response.json({ loreum: 'ipsum' });
};
🐞 Patch Changes
#117919393243 Thanks @bluwy! - Updates Astro’s default <script> rendering strategy and removes the experimental.directRenderScript option as this is now the default behavior: scripts are always rendered directly. This new strategy prevents scripts from being executed in pages where they are not used.
Scripts will directly render as declared in Astro files (including existing features like TypeScript, importing node_modules, and deduplicating scripts). You can also now conditionally render scripts in your Astro file.
However, this means scripts are no longer hoisted to the <head>, multiple scripts on a page are no longer bundled together, and the <script> tag may interfere with the CSS styling.
As this is a potentially breaking change to your script behavior, please review your <script> tags and ensure that they behave as expected.
#117291c54e63 Thanks @ematipico! - Adds a new variant sync for the astro:config:setup hook’s command property. This value is set when calling the command astro sync.
If your integration previously relied on knowing how many variants existed for the command property, you must update your logic to account for this new option.
#11743cce0894 Thanks @ph1p! - Adds a new, optional property timeout for the client:idle directive.
This value allows you to specify a maximum time to wait, in milliseconds, before hydrating a UI framework component, even if the page is not yet done with its initial load. This means you can delay hydration for lower-priority UI elements with more control to ensure your element is interactive within a specified time frame.
<ShowHideButtonclient:idle={{ timeout: 500 }} />
#11677cb356a5 Thanks @ematipico! - Adds a new option fallbackType to i18n.routing configuration that allows you to control how fallback pages are handled.
When i18n.fallback is configured, this new routing option controls whether to redirect to the fallback page, or to rewrite the fallback page’s content in place.
The "redirect" option is the default value and matches the current behavior of the existing fallback system.
The option "rewrite" uses the new rewriting system to create fallback pages that render content on the original, requested URL without a browser refresh.
For example, the following configuration will generate a page /fr/index.html that will contain the same HTML rendered by the page /en/index.html when src/pages/fr/index.astro does not exist.
astro.config.mjs
exportdefaultdefineConfig({
i18n: {
locals: ['en', 'fr'],
defaultLocale: 'en',
routing: {
prefixDefaultLocale: true,
fallbackType: 'rewrite',
},
fallback: {
fr: 'en',
},
},
});
#1170862b0d20 Thanks @martrapp! - Adds a new object swapFunctions to expose the necessary utility functions on astro:transitions/client that allow you to build custom swap functions to be used with view transitions.
The example below uses these functions to replace Astro’s built-in default swap function with one that only swaps the <main> part of the page:
See the view transitions guide for more information about hooking into the astro:before-swap lifecycle event and adding a custom swap implementation.
#118435b4070e Thanks @bholmesdev! - Exposes z from the new astro:schema module. This is the new recommended import source for all Zod utilities when using Astro Actions.
z will no longer be exposed from astro:actions. To use z in your actions, import it from astro:schema instead:
import {
defineAction,
z,
} from 'astro:actions';
import { z } from 'astro:schema';
#118435b4070e Thanks @bholmesdev! - The Astro Actions API introduced behind a flag in v4.8.0 is no longer experimental and is available for general use.
Astro Actions allow you to define and call backend functions with type-safety, performing data fetching, JSON parsing, and input validation for you.
Actions can be called from client-side components and HTML forms. This gives you to flexibility to build apps using any technology: React, Svelte, HTMX, or just plain Astro components. This example calls a newsletter action and renders the result using an Astro component:
#11677cb356a5 Thanks @ematipico! - Fixes a bug in the logic of Astro.rewrite() which led to the value for base, if configured, being automatically prepended to the rewrite URL passed. This was unintended behavior and has been corrected, and Astro now processes the URLs exactly as passed.
If you use the rewrite() function on a project that has base configured, you must now prepend the base to your existing rewrite URL:
Passes AstroConfig instead of AstroSettings object to content layer loaders.
This will not affect you unless you have created a loader that uses the settings object. If you have, you will need to update your loader to use the config object instead.
export default function myLoader() {
return {
name: 'my-loader'
async load({ settings }) {
const base = settings.config.base;
async load({ config }) {
const base = config.base;
// ...
}
}
}
Other properties of the settings object are private internals, and should not be accessed directly. If you think you need access to other properties, please open an issue to discuss your use case.
#117726272e6c Thanks @bluwy! - Uses magicast to update the config for astro add
This was a refactoring of route prioritization in Astro, making it so that injected routes, file-based routes, and redirects are all prioritized using the same logic. This feature has been enabled for all Starlight projects since it was added and should not affect most users.
This feature lets you configure a type-safe schema for your environment variables, and indicate whether they should be available on the server or the client.
To configure a schema, add the env option to your Astro config and define your client and server variables. If you were previously using this feature, please remove the experimental flag from your Astro config and move your entire env configuration unchanged to a top-level option.
#117887c0ccfc Thanks @ematipico! - Updates the default value of security.checkOrigin to true, which enables Cross-Site Request Forgery (CSRF) protection by default for pages rendered on demand.
If you had previously configured security.checkOrigin: true, you no longer need this set in your Astro config. This is now the default and it is safe to remove.
To disable this behavior and opt out of automatically checking that the “origin” header matches the URL sent by each request, you must explicitly set security.checkOrigin: false:
export default defineConfig({
security: {
checkOrigin: false
}
})
#117416617491 Thanks @bluwy! - Removes internal JSX handling and moves the responsibility to the @astrojs/mdx package directly. The following exports are also now removed:
astro/jsx/babel.js
astro/jsx/component.js
astro/jsx/index.js
astro/jsx/renderer.js
astro/jsx/server.js
astro/jsx/transform-options.js
If your project includes .mdx files, you must upgrade @astrojs/mdx to the latest version so that it doesn’t rely on these entrypoints to handle your JSX.
#117829a2aaa0 Thanks @Princesseuh! - Makes the compiledContent property of Markdown content an async function, this change should fix underlying issues where sometimes when using a custom image service and images inside Markdown, Node would exit suddenly without any error message.
---
import * as myPost from "../post.md";
const content = myPost.compiledContent();
const content = await myPost.compiledContent();
---
<Fragment set:html={content} />
#11770cfa6a47 Thanks @Princesseuh! - Removed support for the Squoosh image service. As the underlying library libsquoosh is no longer maintained, and the image service sees very little usage we have decided to remove it from Astro.
Our recommendation is to use the base Sharp image service, which is more powerful, faster, and more actively maintained.
import { squooshImageService } from "astro/config";
#11780c6622ad Thanks @Princesseuh! - Deprecates the Squoosh image service, to be removed in Astro 5.0. We recommend migrating to the default Sharp service.
Server Island requests include the props used to render the island as well as any slots passed in (excluding the fallback slot). Since browsers have a max 4mb URL length we default to using a POST request to avoid overflowing this length.
However in reality most usage of Server Islands are fairly isolated and won’t exceed this limit, so a GET request is possible by passing this same information via search parameters.
Using GET means we can also include a <link rel="preload"> tag to speed up the request.
This change implements this, with safe fallback to POST.
#1177386a3391 Thanks @ematipico! - Changes messages logged when using unsupported, deprecated, or experimental adapter features for clarity
#1177149650a4 Thanks @florian-lefebvre! - Fixes an error thrown by astro sync when an astro:env virtual module is imported inside the Content Collections config
#11744b677429 Thanks @bluwy! - Disables the WebSocket server when creating a Vite server for loading config files
#117943691a62 Thanks @bholmesdev! - Fixes unexpected warning log when using Actions on “hybrid” rendered projects.
#118019f943c1 Thanks @delucis! - Fixes a bug where the filePath property was not available on content collection entries when using the content layer file() loader with a JSON file that contained an object instead of an array. This was breaking use of the image() schema utility among other things.
#11780c6622ad Thanks @Princesseuh! - Deprecates the Squoosh image service, to be removed in Astro 5.0. We recommend migrating to the default Sharp service.
#1179041c3fcb Thanks @sarah11918! - Updates the documentation for experimental astro:env with a corrected link to the RFC proposal
#1177386a3391 Thanks @ematipico! - Changes messages logged when using unsupported, deprecated, or experimental adapter features for clarity
#1174589bab1e Thanks @bluwy! - Prints prerender dynamic value usage warning only if it’s used
#1177149650a4 Thanks @florian-lefebvre! - Fixes an error thrown by astro sync when an astro:env virtual module is imported inside the Content Collections config
#11744b677429 Thanks @bluwy! - Disables the WebSocket server when creating a Vite server for loading config files
#10742b6fbdaa Thanks @ematipico! - The lowest version of Node supported by Astro is now Node v18.17.1 and higher.
#11715d74617c Thanks @Princesseuh! - Refactor the exported types from the astro module. There should normally be no breaking changes, but if you relied on some previously deprecated types, these might now have been fully removed.
In most cases, updating your code to move away from previously deprecated APIs in previous versions of Astro should be enough to fix any issues.
Previously, non-boolean attributes may not have included their values when rendered to HTML. In Astro v5.0, the values are now explicitly rendered as ="true" or ="false"
In the following .astro examples, only allowfullscreen is a boolean attribute:
<!-- src/pages/index.astro --><!-- `allowfullscreen` is a boolean attribute -->
<pallowfullscreen={true}></p>
<pallowfullscreen={false}></p>
<!-- `inherit` is *not* a boolean attribute -->
<pinherit={true}></p>
<pinherit={false}></p>
<!-- `data-*` attributes are not boolean attributes -->
<pdata-light={true}></p>
<pdata-light={false}></p>
Astro v5.0 now preserves the full data attribute with its value when rendering the HTML of non-boolean attributes:
<p allowfullscreen></p>
<p></p>
<p inherit="true"></p>
<p inherit></p>
<p inherit="false"></p>
<p data-light></p>
<p data-light="true"></p>
<p></p>
<p data-light="false"></p>
If you rely on attribute values, for example to locate elements or to conditionally render, update your code to match the new non-boolean attribute values:
This change removes support for the functionPerRoute option both in Astro and @astrojs/vercel.
This option made it so that each route got built as separate entrypoints so that they could be loaded as separate functions. The hope was that by doing this it would decrease the size of each function. However in practice routes use most of the same code, and increases in function size limitations made the potential upsides less important.
Additionally there are downsides to functionPerRoute, such as hitting limits on the number of functions per project. The feature also never worked with some Astro features like i18n domains and request rewriting.
Given this, the feature has been removed from Astro.
🐞 Patch Changes
#1174589bab1e Thanks @bluwy! - Prints prerender dynamic value usage warning only if it’s used
When an HTML minifier strips away the server island comment, the script can’t correctly know where the end of the fallback content is. This makes it so that it simply doesn’t remove any DOM in that scenario. This means the fallback isn’t removed, but it also doesn’t crash the browser.
#11657a23c69d Thanks @bluwy! - Deprecates the option for route-generating files to export a dynamic value for prerender. Only static values are now supported (e.g. export const prerender = true or = false). This allows for better treeshaking and bundling configuration in the future.
Adds a new "astro:route:setup" hook to the Integrations API to allow you to dynamically set options for a route at build or request time through an integration, such as enabling on-demand server rendering.
To migrate from a dynamic export to the new hook, update or remove any dynamic prerender exports from individual routing files:
Use injectTypes() in the astro:config:done hook to inject types into your user’s project by adding a new a *.d.ts file.
The filename property will be used to generate a file at /.astro/integrations/<normalized_integration_name>/<normalized_filename>.d.ts and must end with ".d.ts".
The content property will create the body of the file, and must be valid TypeScript.
Additionally, injectTypes() returns a URL to the normalized path so you can overwrite its content later on, or manipulate it in any way you want.
#11360a79a8b0 Thanks @ascorbic! - Adds support for Intellisense features (e.g. code completion, quick hints) for your content collection entries in compatible editors under the experimental.contentIntellisense flag.
import { defineConfig } from'astro';
exportdefaultdefineConfig({
experimental: {
contentIntellisense: true,
},
});
When enabled, this feature will generate and add JSON schemas to the .astro directory in your project. These files can be used by the Astro language server to provide Intellisense inside content files (.md, .mdx, .mdoc).
Note that at this time, this also require enabling the astro.content-intellisense option in your editor, or passing the contentIntellisense: true initialization parameter to the Astro language server for editors using it directly.
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. There are significant improvements to performance with large collections of local files.
Getting started
To try out the new Content Layer API, enable it in your Astro config:
import { defineConfig } from'astro';
exportdefaultdefineConfig({
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';
constblog=defineCollection({
// The ID is a slug generated from the path of the file relative to `base`
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:
// 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...
});
exportconstcollections= { countries };
For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading, and gives 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 package that exports a loader and publish it to npm, and then anyone can use it on their site. 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:
#1167834da907 Thanks @ematipico! - Fixes a case where omitting a semicolon and line ending with carriage return - CRLF - in the prerender option could throw an error.
Server island props are now encrypted with a key generated at build-time. This is intended to prevent accidentally leaking secrets caused by exposing secrets through prop-passing. This is not intended to allow a server island to be trusted to skip authentication, or to protect against any other vulnerabilities other than secret leakage.
#11655dc0a297 Thanks @billy-le! - Fixes Astro Actions input validation when using default values with a form input.
#11689c7bda4c Thanks @ematipico! - Fixes an issue in the Astro actions, where the size of the generated cookie was exceeding the size permitted by the Set-Cookie header.
#1165813b912a Thanks @bholmesdev! - Fixes orThrow() type when calling an Action without an input validator.
#11603f31d466 Thanks @bholmesdev! - Improves user experience when render an Action result from a form POST request:
Removes “Confirm post resubmission?” dialog when refreshing a result.
Removes the ?_astroAction=NAME flag when a result is rendered.
Also improves the DX of directing to a new route on success. Actions will now redirect to the route specified in your action string on success, and redirect back to the previous page on error. This follows the routing convention of established backend frameworks like Laravel.
For example, say you want to redirect to a /success route when actions.signup succeeds. You can add /success to your action string like so:
On error, Astro will redirect back to the current page.
You can retrieve the action result from either page using the Astro.getActionResult() function.
Note on security
This uses a temporary cookie to forward the action result to the next page. The cookie will be deleted when that page is rendered.
⚠ The action result is not encrypted. In general, we recommend returning minimal data from an action handler to a) avoid leaking sensitive information, and b) avoid unexpected render issues once the temporary cookie is deleted. For example, a login function may return a user’s session id to retrieve from your Astro frontmatter, rather than the entire user object.
#11648589d351 Thanks @bholmesdev! - Fixes unexpected error when refreshing a POST request from a form using Actions.
#1160009ec2ca Thanks @ArmandPhilippot! - Deprecates getEntryBySlug and getDataEntryById functions exported by astro:content in favor of getEntry.
#1159381d7150 Thanks @bholmesdev! - Adds support for Date(), Map(), and Set() from action results. See devalue for a complete list of supported values.
Also fixes serialization exceptions when deploying Actions with edge middleware on Netlify and Vercel.
#11617196092a Thanks @abubakriz! - Fix toolbar audit incorrectly flagging images as above the fold.
#116342716f52 Thanks @bholmesdev! - Fixes internal server error when calling an Astro Action without arguments on Vercel.
#116289aaf58c Thanks @madbook! - Ensures consistent CSS chunk hashes across different environments
#11584a65ffe3 Thanks @bholmesdev! - Removes async local storage dependency from Astro Actions. This allows Actions to run in Cloudflare and Stackblitz without opt-in flags or other configuration.
This also introduces a new convention for calling actions from server code. Instead of calling actions directly, you must wrap function calls with the new Astro.callAction() utility.
callAction() is meant to trigger an action from server code. getActionResult() usage with form submissions remains unchanged.
If you call actions directly from server code, update function calls to use the Astro.callAction() wrapper for pages and context.callAction() for endpoints:
---
import { actions } from 'astro:actions';
const result = await actions.searchPosts({ searchTerm: 'test' });
const result = await Astro.callAction(actions.searchPosts, { searchTerm: 'test' });
#11507a62345f Thanks @ematipico! - Adds color-coding to the console output during the build to highlight slow pages.
Pages that take more than 500 milliseconds to render will have their build time logged in red. This change can help you discover pages of your site that are not performant and may need attention.
#11379e5e2d3e Thanks @alexanderniebuhr! - The experimental.contentCollectionJsonSchema feature introduced behind a flag in v4.5.0 is no longer experimental and is available for general use.
If you are working with collections of type data, Astro will now auto-generate JSON schema files for your editor to get IntelliSense and type-checking. A separate file will be created for each data collection in your project based on your collections defined in src/content/config.ts using a library called zod-to-json-schema.
This feature requires you to manually set your schema’s file path as the value for $schema in each data entry file of the collection:
Alternatively, you can set this value in your editor settings. For example, to set this value in VSCode’s json.schemas setting, provide the path of files to match and the location of your JSON schema:
{
"json.schemas": [
{
"fileMatch": ["/src/content/authors/**"],
"url": "./.astro/collections/authors.schema.json"
}
]
}
If you were previously using this feature, please remove the experimental flag from your Astro config:
import { defineConfig } from 'astro'
export default defineConfig({
experimental: {
contentCollectionJsonSchema: true
}
})
If you have been waiting for stabilization before using JSON Schema generation for content collections, you can now do so.
#1154245ad326 Thanks @ematipico! - The experimental.rewriting feature introduced behind a flag in v4.8.0 is no longer experimental and is available for general use.
Astro.rewrite() and context.rewrite() allow you to render a different page without changing the URL in the browser. Unlike using a redirect, your visitor is kept on the original page they visited.
Rewrites can be useful for showing the same content at multiple paths (e.g. /products/shoes/men/ and /products/men/shoes/) without needing to maintain two identical source files.
Rewrites are supported in Astro pages, endpoints, and middleware.
Return Astro.rewrite() in the frontmatter of a .astro page component to display a different page’s content, such as fallback localized content:
src/pages/es-cu/articles/introduction.astro
---
return Astro.rewrite("/es/articles/introduction")
---
Use context.rewrite() in endpoints, for example to reroute to a different page:
src/pages/api.js
exportfunctionGET(context) {
if (!context.locals.allowed) {
return context.rewrite('/');
}
}
The middleware next() function now accepts a parameter with the same type as the rewrite() function. For example, with next("/"), you can call the next middleware function with a new Request.
src/middleware.js
exportfunctiononRequest(context, next) {
if (!context.cookies.get('allowed')) {
returnnext('/'); // new signature
}
returnnext();
}
If you were previously using this feature, please remove the experimental flag from your Astro config:
astro.config.mjs
export default defineConfig({
experimental: {
rewriting: true
}
})
If you have been waiting for stabilization before using rewrites in Astro, you can now do so.
#115711c3265a Thanks @bholmesdev! - BREAKING CHANGE to the experimental Actions API only. Install the latest @astrojs/react integration as well if you’re using React 19 features.
Make .safe() the default return value for actions. This means { data, error } will be returned when calling an action directly. If you prefer to get the data while allowing errors to throw, chain the .orThrow() modifier.
import { actions } from'astro:actions';
// Before
const { data, error } =await actions.like.safe();
// After
const { data, error } =await actions.like();
// Before
constnewLikes=await actions.like();
// After
constnewLikes=await actions.like.orThrow();
To migrate your existing action calls:
Remove .safe from existing safe action calls
Add .orThrow to existing unsafe action calls
#115467f26de9 Thanks @ArmandPhilippot! - Remove “SSR Only” mention in Astro.redirect inline documentation and update reference link.
#115258068131 Thanks @ematipico! - Fixes a case where the build was failing when experimental.actions was enabled, an adapter was in use, and there were not actions inside the user code base.
#11574e3f29d4 Thanks @Princesseuh! - Fixes line with the error not being properly highlighted in the error overlay
#1157084189b6 Thanks @bholmesdev! - BREAKING CHANGE to the experimental Actions API only. Install the latest @astrojs/react integration as well if you’re using React 19 features.
Updates the Astro Actions fallback to support action={actions.name} instead of using getActionProps(). This will submit a form to the server in zero-JS scenarios using a search parameter:
---
import { actions } from'astro:actions';
---
<formaction={actions.logOut}>
<!--output: action="?_astroAction=logOut"-->
<button>Log Out</button>
</form>
You may also construct form action URLs using string concatenation, or by using the URL() constructor, with the an action’s .queryString property:
getActionProps() is now deprecated. To use the new fallback pattern, remove the getActionProps() input from your form and pass your action function to the form action attribute:
#1155302c85b5 Thanks @ematipico! - Fixes an issue in content collection caching, where two documents with the same contents were generating an error during the build.
#114869c0c849 Thanks @ematipico! - Adds a new function called addClientRenderer to the Container API.
This function should be used when rendering components using the client:* directives. The addClientRenderer API must be used
after the use of the addServerRenderer:
This option allows you to override the values of a theme’s inline style, adding only CSS variables to give you more flexibility in applying multiple color themes.
Configure defaultColor: false in your Shiki config to apply throughout your site, or pass to Astro’s built-in <Code> component to style an individual code block.
#113042e70741 Thanks @Fryuni! - Refactors the type for integration hooks so that integration authors writing custom integration hooks can now allow runtime interactions between their integration and other integrations.
This internal change should not break existing code for integration authors.
To declare your own hooks for your integration, extend the Astro.IntegrationHooks interface:
Call your hooks on all other integrations installed in a project at the appropriate time. For example, you can call your hook on initialization before either the Vite or Astro config have resolved:
Server Islands allow you to specify components that should run on the server, allowing the rest of the page to be more aggressively cached, or even generated statically. Turn any .astro component into a server island by adding the server:defer directive and optionally, fallback placeholder content:
The server:defer directive can be used on any Astro component in a project using hybrid or server mode with an adapter. There are no special APIs needed inside of the island.
Enable server islands by adding the experimental flag to your Astro config with an appropriate output mode and adatper:
#114827c9ed71 Thanks @Princesseuh! - Adds a --noSync parameter to the astro check command to skip the type-gen step. This can be useful when running astro check inside packages that have Astro components, but are not Astro projects
#1109836e30a3 Thanks @itsmatteomanf! - Adds a new inferRemoteSize() function that can be used to infer the dimensions of a remote image.
Previously, the ability to infer these values was only available by adding the [inferSize] attribute to the <Image> and <Picture> components or getImage(). Now, you can also access this data outside of these components.
This is useful for when you need to know the dimensions of an image for styling purposes or to calculate different densities for responsive images.
#114777e9c4a1 Thanks @ematipico! - Fixes an issue where the development server was emitting a 404 status code when the user uses a rewrite that emits a 200 status code.
#11479ca969d5 Thanks @florian-lefebvre! - Fixes a case where invalid astro:env variables at runtime would not throw correctly
#11415e9334d0 Thanks @florian-lefebvre! - Refactors how sync works and when it’s called. Fixes an issue with astro:env types in dev not being generated
#114783161b67 Thanks @bluwy! - Supports importing Astro components with Vite queries, like ?url, ?raw, and ?direct
Vercel, and probably other adapters only allow pre-defined routes. This makes it so that the astro:build:done hook includes the _server-islands/ route as part of the route data, which is used to configure available routes.
#11459bc2e74d Thanks @mingjunlu! - Fixes false positive audit warnings on elements with the role “tabpanel”.
#11472cb4e6d0 Thanks @delucis! - Avoids targeting all files in the src/ directory for eager optimization by Vite. After this change, only JSX, Vue, Svelte, and Astro components get scanned for early optimization.
#114376ccb30e Thanks @NuroDev! - Fixes a case where Astro’s config experimental.env.schema keys did not allow numbers. Numbers are still not allowed as the first character to be able to generate valid JavaScript identifiers
#1143908baf56 Thanks @bholmesdev! - Expands the isInputError() utility from astro:actions to accept errors of any type. This should now allow type narrowing from a try / catch block.
#114520e66849 Thanks @FugiTech! - Fixes an issue where using .nullish() in a formdata Astro action would always parse as a string
#11438619f07d Thanks @bholmesdev! - Exposes utility types from astro:actions for the defineAction handler (ActionHandler) and the ActionError code (ActionErrorCode).
#1145617e048d Thanks @RickyC0626! - Fixes astro dev --open unexpected behavior that spawns a new tab every time a config file is saved
#113370a4b31f Thanks @florian-lefebvre! - Adds a new property experimental.env.validateSecrets to allow validating private variables on the server.
By default, this is set to false and only public variables are checked on start. If enabled, secrets will also be checked on start (dev/build modes). This is useful for example in some CIs to make sure all your secrets are correctly set before deploying.
#11443ea4bc04 Thanks @bholmesdev! - Expose new ActionReturnType utility from astro:actions. This infers the return type of an action by passing typeof actions.name as a type argument. This example defines a like action that returns likes as an object:
actions/index.ts
import { defineAction } from'astro:actions';
exportconstserver= {
like: defineAction({
handler: () => {
/* ... */
return { likes: 42 };
},
}),
};
In your client code, you can infer this handler return value with ActionReturnType:
#1136293993b7 Thanks @ematipico! - Fixes an issue where creating manually the i18n middleware could break the logic of the functions of the virtual module astro:i18n
#1134998d9ce4 Thanks @ematipico! - Fixes an issue where Astro didn’t throw an error when Astro.rewrite was used without providing the experimental flag
#11352a55ee02 Thanks @ematipico! - Fixes an issue where the rewrites didn’t update the status code when using manual i18n routing.
#113270df8142 Thanks @ematipico! - Fixes an issue with the container APIs where a runtime error was thrown during the build, when using pnpm as package manager.
#1132641121fb Thanks @florian-lefebvre! - Fixes a case where running astro sync when using the experimental astro:env feature would fail if environment variables were missing
#113389752a0b Thanks @zaaakher! - Fixes svg icon margin in devtool tooltip title to look coherent in rtl and ltr layouts
Previously we tracked non-fatal errors in telemetry to get a good idea of the types of errors that occur in astro dev. However this has become noisy over time and results in a lot of data that isn’t particularly useful. This removes those non-fatal errors from being tracked.
#1130844c61dd Thanks @ematipico! - Fixes an issue where custom 404.astro and 500.astro were not returning the correct status code when rendered inside a rewriting cycle.
#113020622567 Thanks @martrapp! - Fixes an issue with the view transition router when redirecting to an URL with different origin.
#111349042be0 Thanks @florian-lefebvre! - Improves the developer experience of the 500.astro file by passing it a new error prop.
When an error is thrown, the special src/pages/500.astro page now automatically receives the error as a prop. This allows you to display more specific information about the error on a custom 500 page.
If an error occurs rendering this page, your host’s default 500 error page will be shown to your visitor in production, and Astro’s default error overlay will be shown in development.
🐞 Patch Changes
#11280fd3645f Thanks @ascorbic! - Fixes a bug that prevented cookies from being set when using experimental rewrites
#11275bab700d Thanks @syhily! - Drop duplicated brackets in data collections schema generation.
#11272ea987d7 Thanks @ematipico! - Fixes a case where rewriting / would cause an issue, when trailingSlash was set to "never".
#11272ea987d7 Thanks @ematipico! - Reverts a logic where it wasn’t possible to rewrite /404 in static mode. It’s now possible again
#112645a9c9a6 Thanks @Fryuni! - Fixes type generation for empty content collections
#112799a08d74 Thanks @ascorbic! - Improves type-checking and error handling to catch case where an image import is passed directly to getImage()
#112927f8f347 Thanks @jdtjenkins! - Fixes a case where defineAction autocomplete for the accept prop would not show "form" as a possible value
#11273cb4d078 Thanks @ascorbic! - Corrects an inconsistency in dev where middleware would run for prerendered 404 routes.
Middleware is not run for prerendered 404 routes in production, so this was incorrect.
#11284f4b029b Thanks @ascorbic! - Fixes an issue that would break Astro.request.url and Astro.request.headers in astro dev if HTTP/2 was enabled.
HTTP/2 is now enabled by default in astro dev if https is configured in the Vite config.
Server secrets specified in the schema must now be imported from astro:env/server. Using getSecret() is no longer required to use these environment variables in your schema:
import { getSecret } from 'astro:env/server'
const API_SECRET = getSecret("API_SECRET")
import { API_SECRET } from 'astro:env/server'
Note that using getSecret() with these keys is still possible, but no longer involves any special handling and the raw value will be returned, just like retrieving secrets not specified in your schema.
#112344385bf7 Thanks @ematipico! - Adds a new function called addServerRenderer to the Container API. Use this function to manually store renderers inside the instance of your container.
This new function should be preferred when using the Container API in environments like on-demand pages:
#11242e4fc2a0 Thanks @ematipico! - Fixes a case where the virtual module astro:container wasn’t resolved
#1123639bc3a5 Thanks @ascorbic! - Fixes a case where symlinked content collection directories were not correctly resolved
#11258d996db6 Thanks @ascorbic! - Adds a new error RewriteWithBodyUsed that throws when Astro.rewrite is used after the request body has already been read.
#11243ba2b14c Thanks @V3RON! - Fixes a prerendering issue for libraries in node_modules when a folder with an underscore is in the path.
#11244d07d2f7 Thanks @ematipico! - Improves the developer experience of the custom 500.astro page in development mode.
Before, in development, an error thrown during the rendering phase would display the default error overlay, even when users had the 500.astro page.
Now, the development server will display the 500.astro and the original error is logged in the console.
#112402851b0a Thanks @ascorbic! - Ignores query strings in module identifiers when matching “.astro” file extensions in Vite plugin
#11245e22be22 Thanks @bluwy! - Refactors prerendering chunk handling to correctly remove unused code during the SSR runtime
#1123158d7dbb Thanks @ematipico! - Fixes a regression for getViteConfig, where the inline config wasn’t merged in the final config.
#112281e293a1 Thanks @ascorbic! - Updates getCollection() to always return a cloned array
#112077d9aac3 Thanks @ematipico! - Fixes an issue in the rewriting logic where old data was not purged during the rewrite flow. This caused some false positives when checking the validity of URL path names during the rendering phase.
#1118975a8fe7 Thanks @ematipico! - Improve error message when using getLocaleByPath on path that doesn’t contain any locales.
#106077327c6a Thanks @frankbits! - Fixes an issue where a leading slash created incorrect conflict resolution between pages generated from static routes and catch-all dynamic routes
#111988b9a499 Thanks @florian-lefebvre! - Fixes a case where astro:envgetSecret would not retrieve environment variables properly in dev and build modes
The astro:env API lets you configure a type-safe schema for your environment variables, and indicate whether they should be available on the server or the client. Import and use your defined variables from the appropriate /client or /server module:
To define the data type and properties of your environment variables, declare a schema in your Astro config in experimental.env.schema. The envField helper allows you define your variable as a string, number, or boolean and pass properties in an object:
There are three kinds of environment variables, determined by the combination of context (client or server) and access (private or public) settings defined in your env.schema:
Public client variables: These variables end up in both your final client and server bundles, and can be accessed from both client and server through the astro:env/client module:
import { PUBLIC_API_URL } from'astro:env/client';
Public server variables: These variables end up in your final server bundle and can be accessed on the server through the astro:env/server module:
import { PUBLIC_PORT } from'astro:env/server';
Secret server variables: These variables are not part of your final bundle and can be accessed on the server through the getSecret() helper function available from the astro:env/server module:
Note: Secret client variables are not supported because there is no safe way to send this data to the client. Therefore, it is not possible to configure both context: "client" and access: "secret" in your schema.
#1119258b10a0 Thanks @liruifengv! - Improves DX by throwing the original AstroUserError when an error is thrown inside a .mdx file.
#1113635ef53c Thanks @ematipico! - Errors that are emitted during a rewrite are now bubbled up and shown to the user. A 404 response is not returned anymore.
#11144803dd80 Thanks @ematipico! - The integration now exposes a function called getContainerRenderer, that can be used inside the Container APIs to load the relative renderer.
import { experimental_AstroContainer as AstroContainer } from'astro/container';
Changes the type of the renderers option of the AstroContainer::create function and adds a dedicated function loadRenderers() to load the rendering scripts from renderer integration packages (@astrojs/react, @astrojs/preact, @astrojs/solid-js, @astrojs/svelte, @astrojs/vue, @astrojs/lit, and @astrojs/mdx).
You no longer need to know the individual, direct file paths to the client and server rendering scripts for each renderer integration package. Now, there is a dedicated function to load the renderer from each package, which is available from getContainerRenderer():
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import ReactWrapper from '../src/components/ReactWrapper.astro';
import { loadRenderers } from "astro:container";
import { getContainerRenderer } from "@astrojs/react";
test('ReactWrapper with react renderer', async () => {
const result = await container.renderToString(ReactWrapper);
expect(result).toContain('Counter');
expect(result).toContain('Count: <!-- -->5');
});
The new loadRenderers() helper function is available from astro:container, a virtual module that can be used when running the Astro container inside vite.
#1113635ef53c Thanks @ematipico! - It’s not possible anymore to use Astro.rewrite("/404") inside static pages. This isn’t counterproductive because Astro will end-up emitting a page that contains the HTML of 404 error page.
It’s still possible to use Astro.rewrite("/404") inside on-demand pages, or pages that opt-out from prerendering.
#111916e29a17 Thanks @matthewp! - Fixes a case where Astro.url would be incorrect when having build.format set to 'preserve' in the Astro config
#1118240b0b4d Thanks @ematipico! - Fixes an issue where Astro.rewrite wasn’t carrying over the body of a Request in on-demand pages.
#1119497fbe93 Thanks @ematipico! - Fixes an issue where the function getViteConfig wasn’t returning the correct merged Astro configuration
#11171ff8004f Thanks @Princesseuh! - Guard globalThis.astroAsset usage in proxy code to avoid errors in wonky situations
#111781734c49 Thanks @theoephraim! - Improves isPromise utility to check the presence of then on an object before trying to access it - which can cause undesired side-effects on Proxy objects
#111472d93902 Thanks @kitschpatrol! - Fixes invalid MIME types in Picture source elements for jpg and svg extensions, which was preventing otherwise valid source variations from being shown by the browser
#1114119df89f Thanks @ematipico! - Fixes an internal error that prevented the AstroContainer to render the Content component.
You can now write code similar to the following to render content collections:
#1105112a1bcc Thanks @ematipico! - Introduces an experimental Container API to render .astro components in isolation.
This API introduces three new functions to allow you to create a new container and render an Astro component returning either a string or a Response:
create(): creates a new instance of the container.
renderToString(): renders a component and return a string.
renderToResponse(): renders a component and returns the Response emitted by the rendering phase.
The first supported use of this new API is to enable unit testing. For example, with vitest, you can create a container to render your component with test data and check the result:
import { experimental_AstroContainer as AstroContainer } from'astro/container';
#110212d4c8fa Thanks @ematipico! - The CSRF protection feature that was introduced behind a flag in v4.6.0 is no longer experimental and is available for general use.
To enable the stable version, add the new top-level security option in astro.config.mjs. If you were previously using the experimental version of this feature, also delete the experimental flag:
export default defineConfig({
experimental: {
security: {
csrfProtection: {
origin: true
}
}
},
security: {
checkOrigin: true
}
})
Enabling this setting performs a check that the "origin" header, automatically passed by all modern browsers, matches the URL sent by each Request.
This check is executed only for pages rendered on demand, and only for the requests POST, PATCH, DELETE and PUT with one of the following "content-type" headers: 'application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'.
If the "origin" header doesn’t match the pathname of the request, Astro will return a 403 status code and won’t render the page.
#11022be68ab4 Thanks @ematipico! - The i18nDomains routing feature introduced behind a flag in v3.4.0 is no longer experimental and is available for general use.
This routing option allows you to configure different domains for individual locales in entirely server-rendered projects using the @astrojs/node or @astrojs/vercel adapter with a site configured.
If you were using this feature, please remove the experimental flag from your Astro config:
import { defineConfig } from 'astro'
export default defineConfig({
experimental: {
i18nDomains: true,
}
})
If you have been waiting for stabilization before using this routing option, you can now do so.
#110718ca7c73 Thanks @bholmesdev! - Adds two new functions experimental_getActionState() and experimental_withState() to support the React 19 useActionState() hook when using Astro Actions. This introduces progressive enhancement when calling an Action with the withState() utility.
This example calls a like action that accepts a postId and returns the number of likes. Pass this action to the experimental_withState() function to apply progressive enhancement info, and apply to useActionState() to track the result:
You can also access the state stored by useActionState() from your action handler. Call experimental_getActionState() with the API context, and optionally apply a type to the result:
#11101a6916e4 Thanks @linguofeng! - Updates Astro’s code for adapters to use the header x-forwarded-for to initialize the clientAddress.
To take advantage of the new change, integration authors must upgrade the version of Astro in their adapter peerDependencies to 4.9.0.
#110718ca7c73 Thanks @bholmesdev! - Adds compatibility for Astro Actions in the React 19 beta. Actions can be passed to a form action prop directly, and Astro will automatically add metadata for progressive enhancement.
import { actions } from'astro:actions';
functionLike() {
return (
<formaction={actions.like}>
{/* auto-inserts hidden input for progressive enhancement */}
<buttontype="submit">Like</button>
</form>
);
}
🐞 Patch Changes
#110889566fa0 Thanks @bholmesdev! - Allow actions to be called on the server. This allows you to call actions as utility functions in your Astro frontmatter, endpoints, and server-side UI components.
Import and call directly from astro:actions as you would for client actions:
#1111229a8650 Thanks @bholmesdev! - Deprecate the getApiContext() function. API Context can now be accessed from the second parameter to your Action handler():
When contentCollectionsCache is enabled temporary cached content is copied into the outDir for processing. This fixes it so that this content is cleaned out, along with the rest of the temporary build JS.
#11054f6b171e Thanks @bholmesdev! - Respect error status when handling Actions with a progressive fallback.
#11092bfe9c73 Thanks @duckycoding-dev! - Change slot attribute of IntrinsicAttributes to match the definition of HTMLAttributes’s own slot attribute of type string | undefined | null
#110651f988ed Thanks @ematipico! - Fixes a bug in the Astro rewrite logic, where rewriting the index with parameters - next("/?foo=bar") - didn’t work as expected.
#11052a05ca38 Thanks @florian-lefebvre! - Fixes a case where rewriting would conflict with the actions internal middleware
#1106216f12e4 Thanks @ematipico! - Fixes a bug where astro build didn’t create custom 404.html and 500.html when a certain combination of i18n options was applied
#109995f353e3 Thanks @bluwy! - The prefetch feature is updated to better support different browsers and different cache headers setup, including:
All prefetch strategies will now always try to use <link rel="prefetch"> if supported, or will fall back to fetch().
The prefetch() programmatic API’s with option is deprecated in favour of an automatic approach that will also try to use <link rel="prefetch> if supported, or will fall back to fetch().
This change shouldn’t affect most sites and should instead make prefetching more effective.
#110416cc3fb9 Thanks @bholmesdev! - Fixes 500 errors when sending empty params or returning an empty response from an action.
#11029bd34452 Thanks @bholmesdev! - Actions: include validation error in thrown error message for debugging.
#11046086694a Thanks @HiDeoo! - Fixes getViteConfig() type definition to allow passing an inline Astro configuration as second argument
#110268dfb1a2 Thanks @bluwy! - Fixes CSS handling if imported in a script tag in an Astro file when experimental.directRenderScript is enabled
#110202e2d6b7 Thanks @xsynaptic! - Add type declarations for import.meta.env.ASSETS_PREFIX when defined as an object for handling different file types.
#10981ad9227c Thanks @mo! - Adds deprecated HTML attribute “name” to the list of valid attributes. This attribute has been replaced by the global id attribute in recent versions of HTML.
#110134ea38e7 Thanks @QingXia-Ela! - Prevents unhandledrejection error when checking for latest Astro version
#110345f2dd45 Thanks @arganaphang! - Add popovertargetaction to the attribute that can be passed to the button and input element
#1098705db5f7 Thanks @ematipico! - Fix a regression where the flag experimental.rewriting was marked mandatory. Is is now optional.
#109756b640b3 Thanks @bluwy! - Passes the scoped style attribute or class to the <picture> element in the <Picture /> component so scoped styling can be applied to the <picture> element
#10935ddd8e49 Thanks @bluwy! - Exports astro/jsx/rehype.js with utilities to generate an Astro metadata object
#10625698c2d9 Thanks @goulvenclech! - Adds the ability for multiple pages to use the same component as an entrypoint when building an Astro integration. This change is purely internal, and aligns the build process with the behaviour in the development server.
#109067bbd664 Thanks @Princesseuh! - Adds a new radio checkbox component to the dev toolbar UI library (astro-dev-toolbar-radio-checkbox)
#1096361f47a6 Thanks @delucis! - Adds support for passing an inline Astro configuration object to getViteConfig()
If you are using getViteConfig() to configure the Vitest test runner, you can now pass a second argument to control how Astro is configured. This makes it possible to configure unit tests with different Astro options when using Vitest’s workspaces feature.
vitest.config.ts
import { getViteConfig } from'astro/config';
exportdefaultgetViteConfig(
/* Vite configuration */
{ test: {} },
/* Astro configuration */
{
site: 'https://example.com',
trailingSlash: 'never',
}
);
#1086747877a7 Thanks @ematipico! - Adds experimental rewriting in Astro with a new rewrite() function and the middleware next() function.
The feature is available via an experimental flag in astro.config.mjs:
exportdefaultdefineConfig({
experimental: {
rewriting: true,
},
});
When enabled, you can use rewrite() to render another page without changing the URL of the browser in Astro pages and endpoints.
src/pages/dashboard.astro
---
if (!Astro.props.allowed) {
return Astro.rewrite('/');
}
---
src/pages/api.js
exportfunctionGET(ctx) {
if (!ctx.locals.allowed) {
return ctx.rewrite('/');
}
}
The middleware next() function now accepts a parameter with the same type as the rewrite() function. For example, with next("/"), you can call the next middleware function with a new Request.
src/middleware.js
exportfunctiononRequest(ctx, next) {
if (!ctx.cookies.get('allowed')) {
returnnext('/'); // new signature
}
returnnext();
}
NOTE: please read the RFC to understand the current expectations of the new APIs.
#10858c0c509b Thanks @bholmesdev! - Adds experimental support for the Actions API. Actions let you define type-safe endpoints you can query from client components with progressive enhancement built in.
Actions help you write type-safe backend functions you can call from anywhere. Enable server rendering using the output property and add the actions flag to the experimental object:
{
output: 'hybrid', // or 'server'
experimental: {
actions: true,
},
}
Declare all your actions in src/actions/index.ts. This file is the global actions handler.
Define an action using the defineAction() utility from the astro:actions module. These accept the handler property to define your server-side request handler. If your action accepts arguments, apply the input property to validate parameters with Zod.
This example defines two actions: like and comment. The like action accepts a JSON object with a postId string, while the comment action accepts FormData with postId, author, and body strings. Each handler updates your database and return a type-safe response.
src/actions/index.ts
import { defineAction, z } from'astro:actions';
exportconstserver= {
like: defineAction({
input: z.object({ postId: z.string() }),
handler: async ({ postId }, context) => {
// update likes in db
return likes;
},
}),
comment: defineAction({
accept: 'form',
input: z.object({
postId: z.string(),
body: z.string(),
}),
handler: async ({ postId }, context) => {
// insert comments in db
return comment;
},
}),
};
Then, call an action from your client components using the actions object from astro:actions. You can pass a type-safe object when using JSON, or a FormData object when using accept: 'form' in your action definition:
For a complete overview, and to give feedback on this experimental API, see the Actions RFC.
#109067bbd664 Thanks @Princesseuh! - Adds a new buttonBorderRadius property to the astro-dev-toolbar-button component for the dev toolbar component library. This property can be useful to make a fully rounded button with an icon in the center.
🐞 Patch Changes
#1097759571e8 Thanks @BryceRussell! - Improve error message when accessing clientAddress on prerendered routes
#10935ddd8e49 Thanks @bluwy! - Improves the error message when failed to render MDX components
#109173412535 Thanks @jakobhellermann! - Fixes a case where the local server would crash when the host also contained the port, eg. with X-Forwarded-Host: hostname:8080 and X-Forwarded-Port: 8080 headers
#10959685fc22 Thanks @bluwy! - Refactors internal handling of styles and scripts for content collections to improve build performance
#106657b4f284 Thanks @Princesseuh! - Adds new utilities to ease the creation of toolbar apps including defineToolbarApp to make it easier to define your toolbar app and app and server helpers for easier communication between the toolbar and the server. These new utilities abstract away some of the boilerplate code that is common in toolbar apps, and lower the barrier of entry for app authors.
For example, instead of creating an event listener for the app-toggled event and manually typing the value in the callback, you can now use the onAppToggled method. Additionally, communicating with the server does not require knowing any of the Vite APIs anymore, as a new server object is passed to the init function that contains easy to use methods for communicating with the server.
import { defineToolbarApp } from "astro/toolbar";
export default defineToolbarApp({
init(canvas, app, server) {
app.addEventListener("app-toggled", (e) => {
console.log(`App is now ${state ? "enabled" : "disabled"}`);.
});
app.onToggled(({ state }) => {
console.log(`App is now ${state ? "enabled" : "disabled"}`);
This is a backwards compatible change and your your existing dev toolbar apps will continue to function. However, we encourage you to build your apps with the new helpers, following the updated Dev Toolbar API documentation.
#107346fc4c0e Thanks @Princesseuh! - Astro will now automatically check for updates when you run the dev server. If a new version is available, a message will appear in the terminal with instructions on how to update. Updates will be checked once per 10 days, and the message will only appear if the project is multiple versions behind the latest release.
This behavior can be disabled by running astro preferences disable checkUpdates or setting the ASTRO_DISABLE_UPDATE_CHECK environment variable to false.
#1076243ead8f Thanks @bholmesdev! - Enables type checking for JavaScript files when using the strictest TS config. This ensures consistency with Astro’s other TS configs, and fixes type checking for integrations like Astro DB when using an astro.config.mjs.
If you are currently using the strictest preset and would like to still disable .js files, set allowJS: false in your tsconfig.json.
🐞 Patch Changes
#10861b673bc8 Thanks @mingjunlu! - Fixes an issue where astro build writes type declaration files to outDir when it’s outside of root directory.
#1085630cf82a Thanks @robertvanhoesel! - Prevents inputs with a name attribute of action or method to break ViewTransitions’ form submission
#108338d5f3e8 Thanks @renovate! - Updates esbuild dependency to v0.20. This should not affect projects in most cases.
#10801204b782 Thanks @rishi-raj-jain! - Fixes an issue where images in MD required a relative specifier (e.g. ./)
Now, you can use the standard  syntax in MD files for images colocated in the same folder: no relative specifier required!
There is no need to update your project; your existing images will still continue to work. However, you may wish to remove any relative specifiers from these MD images as they are no longer necessary:


<!-- This dog lives in the same folder as my article! -->
#10841a2df344 Thanks @martrapp! - Due to regression on mobile WebKit browsers, reverts a change made for JavaScript animations during view transitions.
Enabling this setting performs a check that the “origin” header, automatically passed by all modern browsers, matches the URL sent by each Request.
This experimental “origin” check is executed only for pages rendered on demand, and only for the requests POST, PATCH, DELETEandPUTwith one of the followingcontent-type` headers: ‘application/x-www-form-urlencoded’, ‘multipart/form-data’, ‘text/plain’.
It the “origin” header doesn’t match the pathname of the request, Astro will return a 403 status code and won’t render the page.
Adding routing: "manual" to your i18n config disables Astro’s own i18n middleware and provides you with helper functions to write your own: redirectToDefaultLocale, notFound, and redirectToFallback:
Also adds a middleware function that manually creates Astro’s i18n middleware. This allows you to extend Astro’s i18n routing instead of completely replacing it. Run middleware in combination with your own middleware, using the sequence utility to determine the order:
Those are special elements that don’t have an interaction assigned by default. Instead, it is assigned through the role attribute. This means that cases like the following are now deemed correct:
#10495046d69d517118ab5c0e71604b321729d66ddffff Thanks @satyarohith! - This patch allows astro to run in node-compat mode in Deno. Deno doesn’t support
construction of response from async iterables in node-compat mode so we need to
use ReadableStream.
#1055034fa8e131b85531e6629390307108ffc4adb7ed1 Thanks @Skn0tt! - Fixes bug where server builds would include unneeded assets in SSR Function, potentially leading to upload errors on Vercel, Netlify because of size limits
#10493e4a6462751725878bfe47632eeafa6854cad5bf2 Thanks @firefoxic! - <link> tags created by astro for optimized stylesheets now do not include the closing forward slash. This slash is optional for void elements such as link, but made some html validation fail.
#10206dc87214141e7f8406c0fdf6a7f425dad6dea6d3e Thanks @lilnasy! - Allows middleware to run when a matching page or endpoint is not found. Previously, a pages/404.astro or pages/[...catch-all].astro route had to match to allow middleware. This is now not necessary.
When a route does not match in SSR deployments, your adapter may show a platform-specific 404 page instead of running Astro’s SSR code. In these cases, you may still need to add a 404.astro or fallback route with spread params, or use a routing configuration option if your adapter provides one.
#10102e3f02f5fb1cf0dae3c54beb3a4af3dbf3b06abb7 Thanks @bluwy! - Adds a new experimental.directRenderScript configuration option which provides a more reliable strategy to prevent scripts from being executed in pages where they are not used.
This replaces the experimental.optimizeHoistedScript flag introduced in v2.10.4 to prevent unused components’ scripts from being included in a page unexpectedly. That experimental option no longer exists and must be removed from your configuration, whether or not you enable directRenderScript:
astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
optimizeHoistedScript: true,
directRenderScript: true
}
});
With experimental.directRenderScript configured, scripts are now directly rendered as declared in Astro files (including existing features like TypeScript, importing node_modules, and deduplicating scripts). You can also now conditionally render scripts in your Astro file.
However, this means scripts are no longer hoisted to the <head> and multiple scripts on a page are no longer bundled together. If you enable this option, you should check that all your <script> tags behave as expected.
This option will be enabled by default in Astro 5.0.
#101369cd84bd19b92fb43ae48809f575ee12ebd43ea8f Thanks @matthewp! - Changes the default behavior of transition:persist to update the props of persisted islands upon navigation. Also adds a new view transitions option transition:persist-props (default: false) to prevent props from updating as needed.
Islands which have the transition:persist property to keep their state when using the <ViewTransitions /> router will now have their props updated upon navigation. This is useful in cases where the component relies on page-specific props, such as the current page title, which should update upon navigation.
For example, the component below is set to persist across navigation. This component receives a products props and might have some internal state, such as which filters are applied:
Upon navigation, this component persists, but the desired products might change, for example if you are visiting a category of products, or you are performing a search.
Previously the props would not change on navigation, and your island would have to handle updating them externally, such as with API calls.
With this change the props are now updated, while still preserving state.
You can override this new default behavior on a per-component basis using transition:persist-props=true to persist both props and state during navigation:
This feature will auto-generate a JSON Schema for content collections of type: 'data' which can be used as the $schema value for TypeScript-style autocompletion/hints in tools like VSCode.
To enable this feature, add the experimental flag:
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
contentCollectionJsonSchema: true
}
});
This experimental implementation requires you to manually reference the schema in each data entry file of the collection:
Note that this initial implementation uses a library with known issues for advanced Zod schemas, so you may wish to consult these limitations before enabling the experimental flag.
#103558ce9fffd44b0740621178d61fb1425bf4155c2d7 Thanks @ematipico! - Fixes a regression where full dynamic routes were prioritized over partial dynamic routes. Now a route like food-[name].astro is matched before[name].astro.
#10295fdd5bf277e5c1cfa30c1bd2ca123f4e90e8d09d9 Thanks @rossrobino! - Adds a prefetch fallback when using the experimental.clientPrerender option. If prerendering fails, which can happen if Chrome extensions block prerendering, it will fallback to prefetching the URL. This works by adding a prefetch field to the speculationrules script, but does not create an extra request.
#10302992537e79f1847b590a2e226aac88a47a6304f68 Thanks @florian-lefebvre! - Fixes an issue that causes static entrypoints build to fail because of the path in certain conditions. Specifically, it failed if the path had an extension (like .astro, .mdx etc) and such extension would be also within the path (like ./.astro/index.astro).
#10287a90d685d7 Thanks @ematipico! - Fixes an issue where in Node SSR, the image endpoint could be used maliciously to reveal unintended information about the underlying system.
Thanks to Google Security Team for reporting this issue.
#102488ae5d99534fc09d650e10e64a09b61a2807574f2 Thanks @ematipico! - Fixes an issue where multiple injected routes with the same entrypoint but different pattern were incorrectly cached, causing some of them not being rendered in the dev server.
#10165d50dddb71d87ce5b7928920f10eb4946a5339f86 Thanks @ematipico! - Fixes an issue where the i18n.routing object had all its fields defined as mandatory. Now they all are optionals and shouldn’t break when using astro.config.mts.
This uses an AsyncIterable instead of a ReadableStream to do streaming in Node.js. This is a non-standard enhancement by Node, which is done only in that environment.
#10001748b2e87cd44d8bcc1ab9d7e504703057e2000cd Thanks @bholmesdev! - Removes content collection warning when a configured collection does not have a matching directory name. This should resolve i18n collection warnings for Starlight users.
This also ensures configured collection names are always included in getCollection() and getEntry() types even when a matching directory is absent. We hope this allows users to discover typos during development by surfacing type information.
Regular use naming your transitions with transition: name is unaffected.
However, this fix may result in breaking changes if your project relies on the particular character encoding strategy Astro uses to translate transition:name directives into values of the underlying CSS view-transition-name property. For example, Welcome to Astro is now encoded as Welcome_20to_20Astro_2e.
This mainly affects spaces and punctuation marks but no Unicode characters with codes >= 128.
Remote images can now have their dimensions inferred just like local images. Setting inferSize to true allows you to use getImage() and the <Image /> and <Picture /> components without setting the width and height properties.
The sorting algorithm positions more specific routes before less specific routes, and considers index pages to be more specific than a dynamic route with a rest parameter inside of it.
This means that /blog is considered more specific than /blog/[...slug].
But this special case was being applied incorrectly to indexes, which could cause a problem in scenarios like the following:
/
/blog
/blog/[...slug]
The algorithm would make the following comparisons:
/ is more specific than /blog (incorrect)
/blog/[...slug] is more specific than / (correct)
/blog is more specific than /blog/[...slug] (correct)
Although the incorrect first comparison is not a problem by itself, it could cause the algorithm to make the wrong decision.
Depending on the other routes in the project, the sorting could perform just the last two comparisons and by transitivity infer the inverse of the third (/blog/[...slug > / > /blog), which is incorrect.
Now the algorithm doesn’t have a special case for index pages and instead does the comparison soleley for rest parameter segments and their immediate parents, which is consistent with the transitivity property.
Previously index routes deeply nested in the default locale, like /some/nested/index.astro could be mistaked as the root index for the default locale, resulting in an incorrect redirect on /.
#10067989ea63bb2a5a670021541198aa70b8dc7c4bd2f Thanks @ematipico! - Fixes a regression in the astro:i18n module, where the functions getAbsoluteLocaleUrl and getAbsoluteLocaleUrlList returned a URL with double slash with a certain combination of options.
The existing configuration options, file and directory, either build all of your HTML pages as files matching the route name (e.g. /about.html) or build all your files as index.html within a nested directory structure (e.g. /about/index.html), respectively. It was not previously possible to control the HTML file built on a per-file basis.
One limitation of build.format: 'file' is that it cannot create index.html files for any individual routes (other than the base path of /) while otherwise building named files. Creating explicit index pages within your file structure still generates a file named for the page route (e.g. src/pages/about/index.astro builds /about.html) when using the file configuration option.
Rather than make a breaking change to allow build.format: 'file' to be more flexible, we decided to create a new build.format: 'preserve'.
The new format will preserve how the filesystem is structured and make sure that is mirrored over to production. Using this option:
#9143041fdd5c89920f7ccf944b095f29e451f78b0e28 Thanks @ematipico! - Adds experimental support for a new i18n domain routing option ("domains") that allows you to configure different domains for individual locales in entirely server-rendered projects.
To enable this in your project, first configure your server-rendered project’s i18n routing with your preferences if you have not already done so. Then, set the experimental.i18nDomains flag to true and add i18n.domains to map any of your supported locales to custom URLs:
//astro.config.mjs"
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
site: 'https://example.com',
output: 'server', // required, with no prerendered pages
adapter: node({
mode: 'standalone',
}),
i18n: {
defaultLocale: 'en',
locales: ['es', 'en', 'fr', 'ja'],
routing: {
prefixDefaultLocale: false,
},
domains: {
fr: 'https://fr.example.com',
es: 'https://example.es',
},
},
experimental: {
i18nDomains: true,
},
});
With "domains" configured, the URLs emitted by getAbsoluteLocaleUrl() and getAbsoluteLocaleUrlList() will use the options set in i18n.domains.
import { getAbsoluteLocaleUrl } from'astro:i18n';
getAbsoluteLocaleUrl('en', 'about'); // will return "https://example.com/about"
getAbsoluteLocaleUrl('fr', 'about'); // will return "https://fr.example.com/about"
getAbsoluteLocaleUrl('es', 'about'); // will return "https://example.es/about"
getAbsoluteLocaleUrl('ja', 'about'); // will return "https://example.com/ja/about"
Similarly, your localized files will create routes at corresponding URLs:
The file /en/about.astro will be reachable at the URL https://example.com/about.
The file /fr/about.astro will be reachable at the URL https://fr.example.com/about.
The file /es/about.astro will be reachable at the URL https://example.es/about.
The file /ja/about.astro will be reachable at the URL https://example.com/ja/about.
See our Internationalization Guide for more details and limitations on this experimental routing feature.
Now, you can use the standard  syntax in Markdown files for images colocated in the same folder: no relative specifier required!
There is no need to update your project; your existing images will still continue to work. However, you may wish to remove any relative specifiers from these Markdown images as they are no longer necessary:


<!-- This dog lives in the same folder as my article! -->
#98162a44c8f93201958fba2d1e83046eabcaef186b7c Thanks @Princesseuh! - Adds telemetry for when apps are toggled in the dev toolbar. This data is completely anonymous and only the names of built-in apps are shared with us. This data will help us monitor how much the dev toolbar is used and which apps are used more. For more information on how Astro collects telemetry, visit the following page: https://astro.build/telemetry/
#974173d74402007896204ee965f6553dc83b3dec8d2f Thanks @taktran! - Fixes an issue where dot files were not copied over from the public folder to the output folder, when build command was run in a folder other than the root of the project.
Helper functions for converting Node.js HTTP request and response objects to web-compatible Request and Response objects are now provided as static methods on the NodeApp class.
#9638f1a61268061b8834f39a9b38bca043ae41caed04 Thanks @ematipico! - Adds a new i18n.routing config option redirectToDefaultLocale to disable automatic redirects of the root URL (/) to the default locale when prefixDefaultLocale: true is set.
In projects where every route, including the default locale, is prefixed with /[locale]/ path, this property allows you to control whether or not src/pages/index.astro should automatically redirect your site visitors from / to /[defaultLocale].
You can now opt out of this automatic redirection by setting redirectToDefaultLocale: false:
astro.config.mjs
exportdefaultdefineConfig({
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
routing: {
prefixDefaultLocale: true,
redirectToDefaultLocale: false,
},
},
});
#96718521ff77fbf7e867701cc30d18253856914dbd1b Thanks @bholmesdev! - Removes the requirement for non-content files and assets inside content collections to be prefixed with an underscore. For files with extensions like .astro or .css, you can now remove underscores without seeing a warning in the terminal.
src/content/blog/
post.mdx
_styles.css
_Component.astro
styles.css
Component.astro
Continue to use underscores in your content collections to exclude individual content files, such as drafts, from the build output.
#95673a4d5ec8001ebf95c917fdc0d186d29650533d93 Thanks @OliverSpeir! - Improves the a11y-missing-content rule and error message for audit feature of dev-overlay. This also fixes an error where this check was falsely reporting accessibility errors.
#9643e9a72d9a91a3741566866bcaab11172cb0dc7d31 Thanks @blackmann! - Adds a new markdown.shikiConfig.transformers config option. You can use this option to transform the Shikiji hast (AST format of the generated HTML) to customize the final HTML. Also updates Shikiji to the latest stable version.
Enabling this feature overrides the default prefetch behavior globally to prerender links on the client according to your prefetch configuration. Instead of appending a <link> tag to the head of the document or fetching the page with JavaScript, a <script> tag will be appended with the corresponding speculation rules.
Client side prerendering requires browser support. If the Speculation Rules API is not supported, prefetch will fallback to the supported strategy.
See the Prefetch Guide for more prefetch options and usage.
Enabling this feature ensures that all routes in your project follow the same, predictable route priority order rules. In particular, this avoids an issue where redirects or injected routes (e.g. from an integration) would always take precedence over local route definitions, making it impossible to override some routes locally.
The following table shows which route builds certain page URLs when file-based routes, injected routes, and redirects are combined as shown below:
File-based route: /blog/post/[pid]
File-based route: /[page]
Injected route: /blog/[...slug]
Redirect: /blog/tags/[tag] -> /[tag]
Redirect: /posts -> /blog
URLs are handled by the following routes:
Page
Current Behavior
Global Routing Priority Behavior
/blog/tags/astro
Injected route /blog/[...slug]
Redirect to /tags/[tag]
/blog/post/0
Injected route /blog/[...slug]
File-based route /blog/post/[pid]
/posts
File-based route /[page]
Redirect to /blog
In the event of route collisions, where two routes of equal route priority attempt to build the same URL, Astro will log a warning identifying the conflicting routes.
Now, routes with more defined path segments will take precedence over less specific routes.
For example, /blog/posts/[pid].astro (3 path segments) takes precedence over /blog/[...slug].astro (2 path segments). This means that:
/pages/blog/posts/[id].astro will build routes of the form /blog/posts/1 and /blog/posts/a
/pages/blog/[...slug].astro will build routes of a variety of forms, including blog/1 and /blog/posts/1/a, but will not build either of the previous routes.
For a complete list of Astro’s routing priority rules, please see the routing guide. This should not be a breaking change, but you may wish to inspect your built routes to ensure that your project is unaffected.
Tailwind config file ending in .ts, .mts or .cts will now be used instead of creating a new tailwind.config.mjs when the tailwind integration is added using astro add tailwind.
#954608402ad5846c73b6887e74ed4575fd71a3e3c73d Thanks @bluwy! - Adds an option for the Sharp image service to allow large images to be processed. Set limitInputPixels: false to bypass the default image size limit:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
image: {
service: {
entrypoint: 'astro/assets/services/sharp',
config: {
limitInputPixels: false,
},
},
},
});
#9596fbc26976533bbcf2de9d6dba1aa3ea3dc6ce0853 Thanks @Princesseuh! - Adds the ability to set a rootMargin setting when using the client:visible directive. This allows a component to be hydrated when it is near the viewport, rather than hydrated when it has entered the viewport.
<!-- Load component when it's within 200px away from entering the viewport -->
Adds new encode and decode functions to allow customizing how cookies are encoded and decoded. For example, you can bypass the default encoding via encodeURIComponent when adding a URL as part of a cookie:
---
import { encodeCookieValue } from'./cookies';
Astro.cookies.set('url', Astro.url.toString(), {
// Override the default encoding so that URI components are not encoded
#9464faf6c7e11 Thanks @Fryuni! - Fixes an edge case with view transitions where some spec-compliant Content-Type headers would cause a valid HTML response to be ignored.
#94001e984389b Thanks @bluwy! - Fixes importing dev toolbar apps from integrations on Windows
#9458fa3078ce9 Thanks @ematipico! - Correctly handle the error in case the middleware throws a runtime error
#90895ae657882 Thanks @lilnasy! - Fixes an issue where redirects did not replace slugs when the target of the redirect rule was not a verbatim route in the project.
#93390bb3d5322 Thanks @morinokami! - Fixed the log message to correctly display ‘enabled’ and ‘disabled’ when toggling ‘Disable notifications’ in the Toolbar.
#93273878a91be Thanks @doseofted! - Fixes an edge case for <form method="dialog"> when using View Transitions. Forms with method="dialog" no longer require an additional data-astro-reload attribute.
#9138abf601233 Thanks @bluwy! - Updates the unified, remark, and rehype dependencies to latest. Make sure to update your custom remark and rehype plugins as well to be compatible with the latest versions.
Potentially breaking change: The default value of markdown.remarkRehype.footnoteBackLabel is changed from "Back to content" to "Back to reference 1". See the mdast-util-to-hastcommit for more information.
#9181cdabf6ef0 Thanks @bluwy! - Removes support for returning simple objects from endpoints (deprecated since Astro 3.0). You should return a Response instead.
ResponseWithEncoding is also removed. You can refactor the code to return a response with an array buffer instead, which is encoding agnostic.
The types for middlewares have also been revised. To type a middleware function, you should now use MiddlewareHandler instead of MiddlewareResponseHandler. If you used defineMiddleware() to type the function, no changes are needed.
The previously named experimental Dev Overlay is now known as the Astro Dev Toolbar. Overlay plugins have been renamed as Toolbar Apps. All APIs have been updated to reflect this name change.
To not break existing APIs, aliases for the Toolbar-based names have been created. The previous API names will continue to function but will be deprecated in the future. All documentation has been updated to reflect Toolbar-based names.
#91221c48ed286 Thanks @bluwy! - Adds Vite 5 support. There are no breaking changes from Astro. Check the Vite migration guide for details of the breaking changes from Vite instead.
#9225c421a3d17 Thanks @natemoo-re! - Removes the opt-in handleForms property for <ViewTransitions />. Form submissions are now handled by default and this property is no longer necessary. This default behavior can be disabled by setting data-astro-reload on relevant <form /> elements.
#919637697a2c5 Thanks @bluwy! - Removes support for Shiki custom language’s path property. The language JSON file should be imported and passed to the option instead.
astro.config.js
import customLang from './custom.tmLanguage.json'
export default defineConfig({
markdown: {
shikiConfig: {
langs: [
{ path: './custom.tmLanguage.json' },
customLang,
],
},
},
})
#919949aa215a0 Thanks @lilnasy! - This change only affects maintainers of third-party adapters. In the Integration API, the app.render() method of the App class has been simplified.
Instead of two optional arguments, it now takes a single optional argument that is an object with two optional properties: routeData and locals.
app.render(request)
app.render(request, routeData)
app.render(request, { routeData })
app.render(request, routeData, locals)
app.render(request, { routeData, locals })
app.render(request, undefined, locals)
app.render(request, { locals })
The current signature is deprecated but will continue to function until next major version.
With the above configuration, the URL prefix of the default locale will be /english/. When computing Astro.preferredLocale, Astro will use the codes.
#91153b77889b4 Thanks @natemoo-re! - Adds the astro preferences command to manage user preferences. User preferences are specific to individual Astro users, unlike the astro.config.mjs file which changes behavior for everyone working on a project.
User preferences are scoped to the current project by default, stored in a local .astro/settings.json file. Using the --global flag, user preferences can also be applied to every Astro project on the current machine. Global user preferences are stored in an operating system-specific location.
Terminal window
# Disable the dev overlay for the current user in the current project
npmrunastropreferencesdisabledevOverlay
# Disable the dev overlay for the current user in all Astro projects on this machine
npmrunastropreferences--globaldisabledevOverlay
# Check if the dev overlay is enabled for the current user
npmrunastropreferenceslistdevOverlay
#9139459b26436 Thanks @bluwy! - Reworks Vite’s logger to use Astro’s logger to correctly log HMR messages
#92796a9669b81 Thanks @martrapp! - Improves consistency between navigations with and without <ViewTransitions>. See #9279 for more details.
#9161bd0c2e9ae Thanks @bluwy! - Renames the entryPoint property of the injectRoute integrations API to entrypoint for consistency. A warning will be shown prompting you to update your code when using the old name.
#9118000e8f465 Thanks @Princesseuh! - Redesign Dev Overlay main screen to show more information, such as the coolest integrations, your current Astro version and more.
#9118000e8f465 Thanks @Princesseuh! - Fixes an issue where links with the same pathname as the current page, but different search params, were not prefetched.
#92750968cb1a3 Thanks @lilnasy! - Fixes an issue where html annotations relevant only to the dev server were included in the production build.
#92527b74ec4ba Thanks @ematipico! - Consistently emit fallback routes in the correct folders, and emit routes that consider trailingSlash
#924843ddb5217 Thanks @martrapp! - Adds properties of the submit button (name, value) to the form data of a view transition
#91708a228fce0 Thanks @natemoo-re! - Adds new accessibility audits to the Dev Toolbar’s built-in Audits app.
The audits Astro performs are non-exhaustive and only capable of detecting a handful of common accessibility issues. Please take care to perform a thorough, manual audit of your site to ensure compliance with the Web Content Accessibility Guidelines (WCAG) international standardbefore publishing your site.
🧡 Huge thanks to the Svelte team for providing the basis of these accessibility audits!
#91490fe3a7ed5 Thanks @bluwy! - Removes vendored Vite’s importMeta.d.ts file in favour of Vite 5’s new vite/types/import-meta.d.ts export
#9150710be505c Thanks @bluwy! - Refactors virtual modules exports. This should not break your project unless you import Astro’s internal modules, including:
#92796a9669b81 Thanks @martrapp! - Improves consistency between navigations with and without <ViewTransitions>. See #9279 for more details.
🐞 Patch Changes
#91708a228fce0 Thanks @natemoo-re! - Adds new accessibility audits to the Dev Toolbar’s built-in Audits app.
The audits Astro performs are non-exhaustive and only capable of detecting a handful of common accessibility issues. Please take care to perform a thorough, manual audit of your site to ensure compliance with the Web Content Accessibility Guidelines (WCAG) international standardbefore publishing your site.
🧡 Huge thanks to the Svelte team for providing the basis of these accessibility audits!
The previously named experimental Dev Overlay is now known as the Astro Dev Toolbar. Plugins have been renamed as Toolbar Apps. This updates our references to reflect.
To not break existing APIs, aliases for the Toolbar-based names have been created. The previous API names will continue to function but will be deprecated in the future. All documentation has been updated to reflect Toolbar-based names.
#92268f8a40e93 Thanks @outofambit! - Fix i18n fallback routing with routing strategy of always-prefix
#91793f28336d9 Thanks @lilnasy! - Fixes an issue where the presence of a slot in a page led to an error.
#9219067a65f5b Thanks @natemoo-re! - Fix edge case where <style> updates inside of .astro files would ocassionally fail to update without reloading the page.
#923627d3e86e4 Thanks @ematipico! - The configuration i18n.routingStrategy has been replaced with an object called routing.
#9225c421a3d17 Thanks @natemoo-re! - Removes the opt-in handleForms property for <ViewTransitions />. Form submissions are now handled by default and can be disabled by setting data-astro-reload on relevant <form /> elements.
#919949aa215a0 Thanks @lilnasy! - This change only affects maintainers of third-party adapters. In the Integration API, the app.render() method of the App class has been simplified.
Instead of two optional arguments, it now takes a single optional argument that is an object with two optional properties: routeData and locals.
app.render(request)
app.render(request, routeData)
app.render(request, { routeData })
app.render(request, routeData, locals)
app.render(request, { routeData, locals })
app.render(request, undefined, locals)
app.render(request, { locals })
The current signature is deprecated but will continue to function until next major version.
#91153b77889b4 Thanks @natemoo-re! - Adds the astro preferences command to manage user preferences. User preferences are specific to individual Astro users, unlike the astro.config.mjs file which changes behavior for everyone working on a project.
User preferences are scoped to the current project by default, stored in a local .astro/settings.json file. Using the --global flag, user preferences can also be applied to every Astro project on the current machine. Global user preferences are stored in an operating system-specific location.
Terminal window
# Disable the dev overlay for the current user in the current project
npmrunastropreferencesdisabledevOverlay
# Disable the dev overlay for the current user in all Astro projects on this machine
npmrunastropreferences--globaldisabledevOverlay
# Check if the dev overlay is enabled for the current user
#9189d90714fc3 Thanks @SpencerWhitehead7! - Fixes an issue where links with the same pathname as the current page, but different search params, were not prefetched.
#9118000e8f465 Thanks @Princesseuh! - Redesign Dev Overlay main screen to show more information, such as the coolest integrations, your current Astro version and more.
#9118000e8f465 Thanks @Princesseuh! - Fixes an issue where links with the same pathname as the current page, but different search params, were not prefetched.
#9138abf601233 Thanks @bluwy! - Updates the unified, remark, and rehype dependencies to latest. Make sure to update your custom remark and rehype plugins as well to be compatible with the latest versions.
Potentially breaking change: The default value of markdown.remarkRehype.footnoteBackLabel is changed from "Back to content" to "Back to reference 1". See the mdast-util-to-hastcommit for more information.
#9181cdabf6ef0 Thanks @bluwy! - Removes support for returning simple objects from endpoints (deprecated since Astro 3.0). You should return a Response instead.
ResponseWithEncoding is also removed. You can refactor the code to return a response with an array buffer instead, which is encoding agnostic.
The types for middlewares have also been revised. To type a middleware function, you should now use MiddlewareHandler instead of MiddlewareResponseHandler. If you used defineMiddleware() to type the function, no changes are needed.
#91221c48ed286 Thanks @bluwy! - Adds Vite 5 support. There are no breaking changes from Astro. Check the Vite migration guide for details of the breaking changes from Vite instead.
#919637697a2c5 Thanks @bluwy! - Removes support for Shiki custom language’s path property. The language JSON file should be imported and passed to the option instead.
#9161bd0c2e9ae Thanks @bluwy! - Renames the entryPoint property of the injectRoute integrations API to entrypoint for consistency. A warning will be shown prompting you to update your code when using the old name.
🐞 Patch Changes
#91490fe3a7ed5 Thanks @bluwy! - Removes vendored Vite’s importMeta.d.ts file in favour of Vite 5’s new vite/types/import-meta.d.ts export
#9150710be505c Thanks @bluwy! - Refactors virtual modules exports. This should not break your project unless you import Astro’s internal modules, including:
Three new events now complement the existing astro:after-swap and astro:page-load events:
astro: before - preparation; // Control how the DOM and other resources of the target page are loaded
astro: after - preparation; // Last changes before taking off? Remove that loading indicator? Here you go!
astro: before - swap; // Control how the DOM is updated to match the new page
The astro:before-* events allow you to change properties and strategies of the view transition implementation.
The astro:after-* events are notifications that a phase is complete.
Head over to docs to see the full view transitions lifecycle including these new events!
#90920ea4bd47e Thanks @smitbarmase! - Changes the fallback prefetch behavior on slow connections and when data saver mode is enabled. Instead of disabling prefetch entirely, the tap strategy will be used.
The <Picture /> component, part of astro:assets, has exited experimental status and is now recommended for use. There are no code changes to the component, and no upgrade to your project is necessary.
This is only a change in documentation/recommendation. If you were waiting to use the <Picture /> component until it had exited the experimental stage, wait no more!
#90920ea4bd47e Thanks @smitbarmase! - Adds a ignoreSlowConnection option to the prefetch() API to prefetch even on data saver mode or slow connection.
#9091536c6c9fd Thanks @ematipico! - The routingStrategyprefix-always should not force its logic to endpoints. This fixes some regression with astro:assets and @astrojs/rss.
#910260e8210b0 Thanks @Princesseuh! - In the dev overlay, when there’s too many plugins enabled at once, some of the plugins will now be hidden in a separate sub menu to avoid the bar becoming too long
#9085fc66ecff1 Thanks @ematipico! - When redirecting to the default root locale, Astro middleare should take into consideration the value of trailingSlash
#9087b895113a0 Thanks @alexanderniebuhr! - Fixes the regression which broke bundling of image service for pre-rendered pages, which was introduced by #8854
It’s now possible in Astro for an integration to add middleware on behalf of the user. Previously when a third party wanted to provide middleware, the user would need to create a src/middleware.ts file themselves. Now, adding third-party middleware is as easy as adding a new integration.
For integration authors, there is a new addMiddleware function in the astro:config:setup hook. This function allows you to specify a middleware module and the order in which it should be applied:
if (response.headers.get('content-type') ==='text/html') {
let html =await response.text();
html =minify(html);
returnnewResponse(html, {
status: response.status,
headers: response.headers,
});
}
return response;
});
You can now add your integration’s middleware and specify that it runs either before or after the application’s own defined middleware (defined in src/middleware.{js,ts})
my-package/integration.js
exportfunctionmyIntegration() {
return {
name: 'my-integration',
hooks: {
'astro:config:setup': ({ addMiddleware }) => {
addMiddleware({
entrypoint: 'my-package/middleware',
order: 'pre',
});
},
},
};
}
#88543e1239e42 Thanks @natemoo-re! - Provides a new, experimental build cache for Content Collections as part of the Incremental Build RFC. This includes multiple refactors to Astro’s build process to optimize how Content Collections are handled, which should provide significant performance improvements for users with many collections.
Users building a static site can opt-in to preview the new build cache by adding the following flag to your Astro config:
astro.config.mjs
exportdefault {
experimental: {
contentCollectionCache: true,
},
};
When this experimental feature is enabled, the files generated from your content collections will be stored in the cacheDir (by default, node_modules/.astro) and reused between builds. Most CI environments automatically restore files in node_modules/ by default.
In our internal testing on the real world Astro Docs project, this feature reduces the bundling step of astro build from 133.20s to 10.46s, about 92% faster. The end-to-end astro build process used to take 4min 58s and now takes just over 1min for a total reduction of 80%.
If you run into any issues with this experimental feature, please let us know!
You can always bypass the cache for a single build by passing the --force flag to astro build.
The <ViewTransitions /> router can now handle form submissions, allowing the same animated transitions and stateful UI retention on form posts that are already available on <a> links. With this addition, your Astro project can have animations in all of these scenarios:
Clicking links between pages.
Making stateful changes in forms (e.g. updating site preferences).
Manually triggering navigation via the navigate() API.
This feature is opt-in for semver reasons and can be enabled by adding the handleForms prop to the ` component:
Form support works on post method="get" and method="post" forms.
#8954f0031b0a3 Thanks @Princesseuh! - Updates the Image Services API to now delete original images from the final build that are not used outside of the optimization pipeline. For users with a large number of these images (e.g. thumbnails), this should reduce storage consumption and deployment times.
#898426b1484e8 Thanks @Princesseuh! - Adds a new property propertiesToHash to the Image Services API to allow specifying which properties of getImage() / <Image /> / <Picture /> should be used for hashing the result files when doing local transformations. For most services, this will include properties such as src, width or quality that directly changes the content of the generated image.
#9010100b61ab5 Thanks @jasikpark! - The <Picture /> component will now use jpg and jpeg respectively as fallback formats when the original image is in those formats.
Astro’s experimental i18n routing API allows you to add your multilingual content with support for configuring a default language, computing relative page URLs, and accepting preferred languages provided by your visitor’s browser. You can also specify fallback languages on a per-language basis so that your visitors can always be directed to existing content on your site.
Enable the experimental routing option by adding an i18n object to your Astro configuration with a default location and a list of all languages to support:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
experimental: {
i18n: {
defaultLocale: 'en',
locales: ['en', 'es', 'pt-br'],
},
},
});
Organize your content folders by locale depending on your i18n.routingStrategy, and Astro will handle generating your routes and showing your preferred URLs to your visitors.
├── src
│ ├── pages
│ │ ├── about.astro
│ │ ├── index.astro
│ │ ├── es
│ │ │ ├── about.astro
│ │ │ ├── index.astro
│ │ ├── pt-br
│ │ │ ├── about.astro
│ │ │ ├── index.astro
Compute relative URLs for your links with getRelativeLocaleUrl from the new astro:i18n module:
<p>Learn more <ahref={aboutURL}>About</a> this site!</p>
Enabling i18n routing also provides two new properties for browser language detection: Astro.preferredLocale and Astro.preferredLocaleList. These combine the browser’s Accept-Langauge header, and your site’s list of supported languages and can be used to automatically respect your visitor’s preferred languages.
You can enable prefetching for your site with the prefetch: true config. It is enabled by default when using View Transitions and can also be used to configure the prefetch behaviour used by View Transitions.
You can enable prefetching by setting prefetch:true in your Astro config:
astro.config.js
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
prefetch: true,
});
This replaces the @astrojs/prefetch integration, which is now deprecated and will eventually be removed.
Visit the Prefetch guide for more information.
#8903c5010aad3 Thanks @horo-fox! - Adds experimental support for multiple shiki themes with the new markdown.shikiConfig.experimentalThemes option.
🐞 Patch Changes
#90161ecc9aa32 Thanks @Princesseuh! - Add ability to “Click to go editor” on auditted elements in the dev overlay
#902929b83e9e4 Thanks @Princesseuh! - Use UInt8Array instead of Buffer for both the input and return values of the transform() hook of the Image Service API to ensure compatibility with non-Node runtimes.
This change is unlikely to affect you, but if you were previously relying on the return value being a Buffer, you may convert an UInt8Array to a Buffer using Buffer.from(your_array).
#900035739d01e Thanks @martrapp! - Fixes an error in dev mode on Safari where view transitions prevented navigating to pages with client:only components
#9014d979b8f0a Thanks @Princesseuh! - Add animations, shadows and general styling tweaks to the Dev Overlay to better match the intended design.
#89963988bbcc9 Thanks @bluwy! - Adds compatibility for shiki languages with the path property
#8986910eb00fe Thanks @Princesseuh! - Fix sizes attribute not being present on source elements when using it on the Picture component
#8966262cef248 Thanks @Princesseuh! - Fix Dev Overlay not working properly when view transitions are enabled
#89325fed432b0 Thanks @Princesseuh! - Fixed window component appearing over the dev overlay on small windows. Added a maximum length to sections of the tooltip component
A page component can now be identified as a partial page, which will render its HTML content without including a <! DOCTYPE html> declaration nor any <head> content.
A rendering library, like htmx or Stimulus or even just jQuery can access partial content on the client to dynamically update only parts of a page.
Pages marked as partials do not have a doctype or any head content included in the rendered result. You can mark any page as a partial by setting this option:
---
exportconstpartial=true;
---
<li>This is a single list item.</li>
Other valid page files that can export a value (e.g. .mdx) can also be marked as partials.
Astro will now generate optimized images concurrently at build time, which can significantly speed up build times for sites with many images. Additionally, Astro will now reuse the same buffer for all variants of an image. This should improve performance for websites with many variants of the same image, especially when using remote images.
No code changes are required to take advantage of these improvements.
Provides a new dev overlay for your browser preview that allows you to inspect your page islands, see helpful audits on performance and accessibility, and more. A Dev Overlay Plugin API is also included to allow you to add new features and third-party integrations to it.
You can enable access to the dev overlay and its API by adding the following flag to your Astro config:
#88808c3d4a859 Thanks @alexanderniebuhr! - Moves the logic for overriding the image service out of core and into adapters. Also fixes a regression where a valid astro:assets image service configuration could be overridden.
#8502c4270e476 Thanks @bluwy! - Updates the internal shiki syntax highlighter to shikiji, an ESM-focused alternative that simplifies bundling and maintenance.
There are no new options and no changes to how you author code blocks and syntax highlighting.
Potentially breaking change: While this refactor should be transparent for most projects, the transition to shikiji now produces a smaller HTML markup by attaching a fallback color style to the pre or code element, instead of to the line span directly. For example:
This does not affect the colors as the span will inherit the color from the parent, but if you’re relying on a specific HTML markup, please check your site carefully after upgrading to verify the styles.
#8798f369fa250 Thanks @Princesseuh! - Fixed tsconfig.json’s new array format for extends not working. This was done by migrating Astro to use tsconfck instead of tsconfig-resolver to find and parse tsconfig.json files.
#8620b2ae9ee0c Thanks @Princesseuh! - Adds experimental support for generating srcset attributes and a new <Picture /> component.
Two new properties have been added to Image and getImage(): densities and widths.
These properties can be used to generate a srcset attribute, either based on absolute widths in pixels (e.g. [300, 600, 900]) or pixel density descriptors (e.g. ["2x"] or [1.5, 2]).
#8472 caused some style files from previous pages to not be cleanly deleted on view transitions. For a discussion of a future fix for the original issue #8144 see #8745.
#8741c4a7ec425 Thanks @lilnasy! - Fixed an issue on Windows where lowercase drive letters in current working directory led to missing scripts and styles.
#869847ea310f0 Thanks @Princesseuh! - Use a Node-specific image endpoint to resolve images in dev and Node SSR. This should fix many issues related to getting 404 from the _image endpoint under certain configurations
Astro integrations can now themselves dynamically add and configure additional integrations during set-up. This makes it possible for integration authors to bundle integrations more intelligently for their users.
In the following example, a custom integration checks whether @astrojs/sitemap is already configured. If not, the integration adds Astro’s sitemap integration, passing any desired configuration options:
The View Transitions router now does route announcement. When transitioning between pages with a traditional MPA approach, assistive technologies will announce the page title when the page finishes loading. This does not automatically happen during client-side routing, so visitors relying on these technologies to announce routes are not aware when a page has changed.
The view transitions route announcer runs after the astro:page-load event, looking for the page <title> to announce. If one cannot be found, the announcer falls back to the first <h1> it finds, or otherwise announces the pathname. We recommend you always include a <title> in each page for accessibility.
#8467ecc65abbf Thanks @Princesseuh! - Add a new image.endpoint setting to allow using a custom endpoint in dev and SSR
#85182c4fc878b Thanks @Princesseuh! - Adds support for using AVIF (.avif) files with the Image component. Importing an AVIF file will now correctly return the same object shape as other image file types. See the Image docs for more information on the different properties available on the returned object.
#8464c92e0acd7 Thanks @Princesseuh! - Add types for the object syntax for style (ex: style={{color: 'red'}})
#83517d95bd9ba Thanks @lilnasy! - Fixed a case where dynamic imports tried to preload inlined stylesheets.
#83531947ef7a9 Thanks @elevatebart! - Astro will now skip asset optimization when there is a query in the import. Instead, it will let vite deal with it using plugins.