#17427630b382 Thanks @astrobot-houston! - Fixes image optimization during astro build using too many parallel processes in CPU-limited containers. Builds now respect the container’s CPU limit, reducing peak memory usage and avoiding out-of-memory crashes.
#17445a5f7230 Thanks @ocavue! - Updates dependency cookie to v2. Cookie values made entirely of URL-safe characters are no longer percent-encoded in Set-Cookie headers; encoded values round-trip exactly as before.
#17402a89c137 Thanks @farrosfr! - Fixes a bug where mutated Astro.locals during the request lifecycle are lost and not passed to custom error pages (404.astro/500.astro)
#1740591992ef Thanks @Araluma! - Prevents an unhandled promise rejection from the prefetch fetch fallback. In WebKit (Safari), <link rel="prefetch"> is unsupported, so prefetch uses the fetch() fallback; on a flaky connection that fetch rejects with TypeError: Load failed, and because the promise was not awaited or caught, it surfaced as an unhandled rejection to the page’s global error handlers. The best-effort prefetch now swallows the failure with .catch().
When set to true, renderable entries (such as Markdown) are not rendered during content sync. Instead, rendering is deferred until the entry is actually rendered in a page, using the same on-demand path that .mdx files already use.
This reduces memory usage during astro build for large collections whose rendered output is much larger than the source — for example, Markdown that uses heavy rehype plugins like rehype-katex. Such builds could previously run out of memory while storing the eagerly-rendered HTML for every entry.
By default deferRender is false, preserving the existing behavior of rendering entries eagerly during sync so their rendered HTML can be cached across builds.
#1729630698a2 Thanks @ematipico! - Adds a new experimental collectionStorage option for controlling how the content layer persists its data store
By default, Astro serializes the entire content layer data store to a single file (.astro/data-store.json). For very large content collections, this file can grow large enough to hit platform file-size limits.
Set experimental.collectionStorage: 'chunked' to instead split the data store across many smaller, content-addressed files inside a .astro/data-store/ directory, described by a manifest:
astro.config.mjs
import { defineConfig } from'astro/config';
exportdefaultdefineConfig({
experimental: {
collectionStorage: 'chunked',
},
});
Because each part file is named by a hash of its contents, unchanged parts keep the same name across builds and are not rewritten, and identical parts are deduplicated. The default value is 'single-file', which preserves the current behavior.
#1721444c4989 Thanks @ematipico! - Adds support for the more specific CSP directives script-src-elem, script-src-attr, style-src-elem, and style-src-attr through a new kind option.
Previously, CSP was only scoped to generic script-src/style-src directives. Now each source or hash can be scoped to a narrower directive — for example, to allow inline style attributes (such as those from define:vars or Shiki) without loosening the policy for your <style> and <link> elements.
Scoping sources and hashes in your config
Each entry in resources and hashes can be an object with a kind property. Depending on whether you use scriptDirective or styleDirective, "element" targets script-src-elem or style-src-elem, "attribute" targets script-src-attr or style-src-attr, and "default" (the same as a bare string or hash) targets script-src or style-src.
#1725884814d4 Thanks @astrobot-houston! - Adds a new format() option to the paginate utility. The format() option is a function that accepts the current URL of the page, and returns a new URL.
For example, when your host only supports URLs using the .html extension, you can use format() to add it to the generated URLs:
---
exportasyncfunctiongetStaticPaths({ paginate }) {
// Load your data with fetch(), getCollection(), etc.
// Return a paginated collection of paths for all items
returnpaginate(allPokemon, {
pageSize: 10,
format: (url) =>`${url}.html`,
});
}
const { page } = Astro.props;
---
#173317db6420 Thanks @matthewp! - Adds a --ignore-lock flag to astro dev for starting a dev server without checking or writing the lock file, so it can run alongside an already-running dev server for the same project.
The new instance is not tracked by astro dev stop, astro dev status, or astro dev logs. --ignore-lock cannot be combined with --background (or an auto-detected AI agent environment, which runs dev servers in the background automatically) or --force, since those rely on the lock file.
#173324407483 Thanks @astrobot-houston! - Fixes the JSON logger crashing with process is not defined in non-Node runtimes like Cloudflare’s workerd. The JSON logger now uses console.log/console.error instead of process.stdout/process.stderr, matching the pattern already used by the console logger.
#17391186a1e7 Thanks @florian-lefebvre! - Fixes a case where an integration could not update the logger with updateConfig()
#17394d9f99e1 Thanks @matthewp! - Fixes element-specific CSP directives to preserve the existing behavior of configured script and style resources
#17374b2d1b3e Thanks @astrobot-houston! - Fixes dev server returning 404 for ?url imported assets when accessed via browser navigation
#17390ed71eaf Thanks @florian-lefebvre! - Removes an unused and undocumented generic from the AstroLoggerDestination type
#17393092da56 Thanks @matthewp! - Hardens generated transition styles, development metadata, and server island URLs when embedding dynamic values
#17286a249317 Thanks @astrobot-houston! - Fixes the first browser visit after astro dev starts triggering an immediate full page reload
#17369a94d4a5 Thanks @adamchal! - Fixes an issue where a client island could permanently fail to hydrate if the first attempt to load its component failed. Islands now reliably recover from transient import failures, which previously did not work for React components during astro dev.
#173633f4efc5 Thanks @astrobot-houston! - Fixes astro preview --open not opening a browser when using an adapter with a custom preview entrypoint, such as @astrojs/cloudflare
#17313e2e319d Thanks @ronits2407! - Exposes the AstroRuntimeLogger interface to allow users to properly type the logger functions at runtime.
#17328025cc74 Thanks @matthewp! - Fixes astro dev --force not replacing an already-running dev server
#173532bba277 Thanks @ematipico! - Updates the Astro compiler to the latest version, which fixes many regressions. Refer to the changelog for more details.
#1734479a41e0 Thanks @adamchal! - Improves rendering performance for pages with many component instances, such as repeated MDX <Content /> components.
#1731823a4120 Thanks @astrobot-houston! - Fixes CSS module scoped-name hash mismatch in astro dev when using vite.css.transformer: 'lightningcss' with content collections. Previously, a component importing a CSS module and rendered via content collection render() would get different class name hashes in the element and the injected <style> tag, causing styles not to apply.
#173234298883 Thanks @ematipico! - Fixes a dev server memory leak which caused Node.js to emit warnings in the console.
#173234298883 Thanks @ematipico! - Fixes a dev server crash when a .html or /index.html suffixed request (such as those netlify dev probes as pretty-URL fallbacks) matched a dynamic endpoint route, causing a TypeError: Missing parameter error
#17325cebc404 Thanks @astrobot-houston! - Fixes a bug where CSS @import rules could end up mid-stylesheet after inline CSS chunks were merged during build, causing browsers to silently ignore them
#173234298883 Thanks @ematipico! - Fixes a build regression that could leave unresolved preload markers in inlined scripts with external dynamic imports
#1726179aa99c Thanks @astrobot-houston! - Fixes a false deprecation warning for markdown.gfm and markdown.smartypants when using the Container API
#17247f94280d Thanks @chatman-media! - Fixes route generation throwing “Missing parameter” (or silently dropping the segment) when a dynamic param’s value is 0. The generator used truthy checks instead of checking for undefined, so paginate(posts, { params: { categoryId: 0 } }) would crash even though 0 is a perfectly valid param value.
#172786f11739 Thanks @astrobot-houston! - Fixes missing CSS for virtual style modules (e.g., responsive image layout styles) in dev mode when JavaScript is disabled
#172500b30b35 Thanks @matthewp! - Fixes the security.checkOrigin check so it is applied consistently to Astro Actions and on-demand endpoints, regardless of how the request pipeline is composed. Previously, the origin check could be skipped in the composable astro/hono pipeline depending on the order of the middleware() primitive (or when it was omitted).
#172748c3579b Thanks @astrobot-houston! - Fixes missing render() type overload for live collection entries. Previously, calling render() on a LiveDataEntry produced a TypeScript error when using only live.config.ts without a content.config.ts.
#172574208297 Thanks @astrobot-houston! - Fixes astro check failing to find @astrojs/check and typescript when astro is installed in a directory outside the project tree (e.g. pnpm virtual store)
#17272b428648 Thanks @matthewp! - Fixes island component paths so that extensionless imports (e.g. import { Counter } from '../components/Counter') resolve to the real file on disk, matching Vite’s extension order and directory index resolution. This makes the include/exclude options of JSX renderer integrations (React, Preact, Solid) match components imported without a file extension, and removes the spurious React 19 “Invalid hook call” warning logged on every request in dev when include was set alongside another JSX renderer
#172792aeaa44 Thanks @astrobot-houston! - Fixes a bug where <Picture inferSize> with a remote image could fail with FailedToFetchRemoteImageDimensions when the image server rate-limits requests (e.g. HTTP 429). Remote dimensions are now resolved once per render instead of once per output format.
#172515240e26 Thanks @matthewp! - Hardens the handling of attribute rendering when using with custom elements.
#17248429bd62 Thanks @astrobot-houston! - Fixes a crash when using Astro’s getViteConfig with Vitest browser mode (e.g., Storybook vitest runner). Astro now skips dev server setup inside Vitest, preventing errors.
#1726014524c0 Thanks @matthewp! - Fixes a regression where a <script> inside a component rendered through Astro.slots.render() was hoisted out of its original position instead of staying next to its component content
#172429c05ba4 Thanks @matthewp! - Fixes an error that could occur after the dev server restarts when using an adapter such as @astrojs/cloudflare, where a request would fail with a 500 referencing a missing pre-bundled dependency:
The file does not exist at "node_modules/.vite/deps_ssr/astro_compiler-runtime.js?v=6419660d" which is in the optimize deps directory. The dependency might be incompatible with the dep optimizer. Try adding it to `optimizeDeps.exclude`.
#17202c6d254d Thanks @matthewp! - Refactors path alias resolution to use Vite’s native tsconfigPaths option
This is an internal change with no expected impact on user projects. Astro now defers tsconfig and jsconfig paths alias resolution to Vite, keeping a small fallback for a few CSS cases Vite does not yet handle.
#1712372e29bd Thanks @martrapp! - Fixes an issue where the ClientRouter wipes head elements after page transitions if the <head> contains a server:defer component.
#17232257505e Thanks @matthewp! - Fixes a bug where <style> tags from components such as a content collection’s Content could be silently dropped from the output when an await appeared before the component in an .astro file’s markup.
#17193a7352fd Thanks @jan-kubica! - Fixes the background dev server failing to start when astro is hoisted outside the project’s node_modules (for example bun workspaces). The background process is now spawned from Astro’s own resolved location instead of a path assumed under the project root.
#172127ba0bb1 Thanks @matthewp! - Ensures transition directive values are HTML-escaped when rendered on hydrated islands
#17224dc5e52f Thanks @astrobot-houston! - Fixes trailing slash handling for dynamic file endpoints in dev mode. Dynamic file endpoints (e.g., src/pages/api/[name].json.ts) with trailingSlash: "always" incorrectly required a trailing slash in dev mode, returning 404 for /api/bar.json and 200 for /api/bar.json/.
#1706723f9446 Thanks @fkatsuhiro! - Fixed a bug where the development toolbar did not output a warning even though the implicit ARIA role and the manually specified role were duplicated.
#172235970ef4 Thanks @astrobot-houston! - Fixes getCollection() returning empty in dev mode for large content collections (500k+ entries)
#17184799e5cd Thanks @Princesseuh! - Upgrades the Rust compiler to the latest, which fixes some bugs. Refer to its changelog for more information.
#17208da8b573 Thanks @matthewp! - Hardens forwarded header handling so the internal request helper validates X-Forwarded-Host against security.allowedDomains before trusting X-Forwarded-For for clientAddress. Previously it only checked that the header was present, which was inconsistent with the public createRequest helper. This aligns both code paths; behavior is unchanged for correctly configured proxies.
#1718924d2c9e Thanks @astrobot-houston! - Fixes a bug where an error thrown inside one route’s getStaticPaths() would prevent other valid routes from being matched in dev mode
#169328f4a3db Thanks @fkatsuhiro! - Fixes HMR for action files during development. Editing files in src/actions/ now takes effect on the next request without requiring a dev server restart.
#17087fb0ab02 Thanks @jp-knj! - Fixes localized custom error pages in i18n projects so routes like /pt/404 are used for missing localized pages and return the correct status code
#17151ccceda3 Thanks @matthewp! - Fixes astro dev incorrectly starting in background mode for Warp terminal users. Hybrid environments like Warp are no longer treated as AI agents for auto-background detection.
#17158164df87 Thanks @ematipico! - Fixes astro dev --background --host not listing the network addresses. The background server start output and astro dev status now show every exposed network URL, matching the foreground dev server.
#17141d785b9d Thanks @astrobot-houston! - Fixes responsive image CSS overriding user styles defined inside CSS @layer blocks. The generated image styles are now wrapped in @layer astro.images, ensuring they have lower cascade priority than user-defined layers.
#171501a61386 Thanks @matthewp! - Fixes astro dev --background failing on Windows with “Failed to spawn background dev server process”
Astro now strips whitespace from your HTML using JSX rules by default, the same way frameworks like React do. Whitespace and line breaks around elements are removed, but meaningful whitespace within a single line — like a space between two inline elements — is preserved. To keep a space that would otherwise be removed, write it explicitly in your source, for example with {" "}.
This can change rendered output where whitespace between inline elements was previously meaningful. To keep Astro’s earlier behavior, set compressHTML: true for HTML-aware compression, or compressHTML: false to preserve all whitespace.
#16610c63e7e4 Thanks @matthewp! - Adds background dev server management for AI coding agents.
When an AI coding agent is detected, astro dev now automatically starts the dev server as a detached background process. This prevents the dev server from blocking the agent’s terminal and allows it to continue working while the server runs.
A lock file (.astro/dev.json) is written when the dev server starts, recording the server’s URL, port, and PID. This prevents duplicate servers from being started for the same project.
New flag and subcommands
astro dev --background — Start the dev server as a background process (this is what runs automatically when an agent is detected).
astro dev stop — Stop a running background dev server.
astro dev status — Check if a dev server is running and display its URL, PID, and uptime.
astro dev logs — View logs from a background dev server. Use --follow (-f) to stream new output as it’s written.
These allow you to start and manage dev servers programmatically and were designed with AI coding agents in mind.
What should I do?
No action is required. If you are not using an AI coding agent, astro dev behaves exactly as before. If you are using an agent, background mode is enabled automatically — the agent will receive the server URL and PID, and can use astro dev stop to shut it down.
To opt out of automatic background mode when an agent is detected, set the environment variable ASTRO_DEV_BACKGROUND=0 before running astro dev.
#170100606073 Thanks @ocavue! - Removes the @astrojs/db package as it is no longer maintained.
The @astrojs/db package were deprecated in v6.4.5 and is now removed. This means the astro db, astro login, astro logout, astro link, and astro init CLI commands have also been removed.
If you were using Astro DB in your project, remove @astrojs/db from your project’s dependencies and replace it with one of the following alternatives:
Node.js built-in SQLite: Node.js now includes a built-in node:sqlite module (available since Node.js v22.5.0). This is a good option if you are using the Node.js adapter and were using @astrojs/db for local SQLite storage.
Drizzle ORM: If you were using @astrojs/db for its Drizzle-based schema and query API, you can use Drizzle directly with any supported database.
Other database libraries: Use any database library that suits your deployment platform (e.g. Turso, PlanetScale, Neon).
The Rust-based Astro compiler (@astrojs/compiler-rs) is now the default compiler. This new compiler is faster and more reliable, leading to faster build times and iteration cycles during development.
This new compiler is more strict regarding invalid syntax. For example, unclosed HTML tags will now throw an error instead of being ignored. It also does not attempt to correct semantically invalid HTML anymore, instead leaving it to the browser to handle, similar to other tools or document.write() in JavaScript.
The previous Go-based compiler has been removed, along with the experimental.rustCompiler flag used to opt into the Rust compiler. If you were setting experimental.rustCompiler in your astro.config.mjs, you can now remove it. No other action is required.
Astro now renders .md files with satteri() from @astrojs/markdown-satteri, its native Markdown pipeline, instead of the remark/rehype pipeline. @astrojs/markdown-remark is no longer installed by default.
To keep using the remark/rehype pipeline, install @astrojs/markdown-remark and set it as your processor:
The deprecated markdown.remarkPlugins, markdown.rehypePlugins, and markdown.remarkRehype options still work, but now require @astrojs/markdown-remark to be used.
The advanced routing feature introduced behind a flag in v6.3.0 is no longer experimental and is now enabled by default.
This gives full control over how requests flow through your application, with first-class support for frameworks like Hono.
Advanced routing now uses src/fetch.ts as default entrypoint instead of src/app.ts.
If you were previously using this feature without a custom entrypoint, please configure fetchFile or rename your entrypoint to src/fetch.ts, and then remove the experimental flag from your Astro config:
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental {
advancedRouting: true,
},
fetchFile: 'app.ts' // optional, you only need this if you cannot rename your entrypoint.
});
fetchFile is now a top-level config option instead of being nested under experimental.advancedRouting. If you were using a custom entrypoint, please update your Astro config to move its configuration:
astro.config.mjs
export default defineConfig({
experimental: {
advancedRouting: {
fetchFile: 'my-custom-entrypoint.ts',
},
},
fetchFile: 'my-custom-entrypoint.ts',
})
You can also set fetchFile: null to disable the entrypoint if you are using src/fetch.ts for another purpose, or don’t need advanced routing features.
If you have been waiting for stabilization before using advanced routing, you can now do so.
#1699857dcc31 Thanks @matthewp! - Exposes getFetchState() from astro/hono as a public API
The getFetchState() function retrieves or lazily creates a FetchState from a Hono context object. This allows third-party packages to build Hono middleware that interacts with Astro’s per-request state, giving the astro/hono API the same extensibility as astro/fetch.
import { Hono } from'hono';
import { getFetchState, pages } from'astro/hono';
constapp=newHono();
app.use(async (context, next) => {
conststate=getFetchState(context);
state.locals.message ='Hello from custom middleware';
awaitnext();
});
app.use(pages());
exportdefault app;
#16996300641e Thanks @florian-lefebvre! - Adds a subset field to the FontData type exposed via fontData from astro:assets. When using multiple font subsets (e.g., subsets: ["latin", "korean"]), each font data entry now includes the subset name, making it possible to distinguish between font entries for different subsets that share the same weight and style.
#16745f864a80 Thanks @ematipico! - The custom logger feature introduced behind a flag in v6.2.0 is no longer experimental and is available for general use.
This feature provides better control over Astro’s logging infrastructure by allowing you to replace the default console output with custom logging implementations (e.g., structured JSON). This is particularly useful for on-demand rendering when connecting to log aggregation services such as Kibana, Logstash, CloudWatch, Grafana, or Loki.
Astro provides three built-in log handlers (json, node, and console), and you can also create your own.
Additionally, context.logger is now always available in API routes and middleware, even without a custom logger configured.
If you were previously using this feature, please remove the experimental flag from your Astro config:
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
logger: {
entrypoint: '@org/custom-logger',
},
},
logger: {
entrypoint: '@org/custom-logger',
},
});
If you have been waiting for stabilization before using custom loggers, you can now do so.
Please see the Logger docs for more about this feature.
#169810d6d644 Thanks @ematipico! - Removes the setting experimental.queuedRendering. The new rendering engine is now stable and replaces the old one.
As part of the stabilization, the queued rendering has been improved, and some features have been removed:
The construction of the queue has been removed, instead now Astro uses a streaming approach where components are rendered and flushed as they are encountered.
The node polling feature has been removed because it doesn’t yield concrete savings.
The content cache has been descoped, and how only tag names are cached.
If you were previously using this experimental feature, you must remove this experimental flag from your configuration as it no longer exists:
astro.config.mjs
import { defineConfig } from "astro/config";
export default defineConfig({
experimental: {
queuedRendering: {}
}
});
#17116f95e58e Thanks @ascorbic! - Stabilizes route caching, removing the experimental.cache and experimental.routeRules flags and replacing them with the top-level cache and routeRules configuration options.
Route caching, introduced experimentally in v6.0.0, is now stable. It gives you a platform-agnostic way to cache responses from on-demand rendered pages and endpoints, based on standard HTTP caching semantics.
Update your config to move cache and routeRules out of the experimental block:
astro.config.mjs
import { defineConfig, memoryCache } from 'astro/config';
export default defineConfig({
experimental: {
cache: {
provider: memoryCache(),
},
routeRules: {
'/blog/[...path]': { maxAge: 300, swr: 60 },
},
},
cache: {
provider: memoryCache(),
},
routeRules: {
'/blog/[...path]': { maxAge: 300, swr: 60 },
},
});
Set caching directives in your routes with Astro.cache (in .astro pages) or context.cache (in API routes and middleware), and Astro translates them into the appropriate headers or runtime behavior depending on your configured cache provider. You can also define cache rules for routes declaratively in your config using routeRules, without modifying route code.
#169801f07343 Thanks @matthewp! - Removes state.provide(), state.resolve(), state.finalizeAll(), and App.Providers from the public advanced routing API. These context provider extension points are now internal-only. If you were using them in an integration, use locals to share per-request state instead.
#169821e000e2 Thanks @matthewp! - Improves the warning when accessing Astro.session without session storage configured. The session property is now always defined on the context object, and accessing it without configuration logs a helpful message instead of silently returning undefined.
Exports astro/cache/provider-utils with helpers for building platform-specific cache-control headers, generating path-based invalidation tags, and normalizing invalidation options. These are used internally by the first-party Netlify, Vercel, and Cloudflare cache providers.
#17095e84ebc0 Thanks @matthewp! - Improves build performance by removing an unfiltered transform hook from the astro:head-metadata-build plugin. Head propagation modules are now identified by their module ID (?astroPropagatedAssets) instead of scanning every module’s source code.
#170414c4a91c Thanks @iseraph-dev! - Fixes a bug where the advanced routing astro/hono / astro/fetchpages() handler returned the host framework’s default Internal Server Error response instead of rendering the custom 500.astro page when a page threw during render. Unmatched requests with a prerendered (or absent) custom 404 page now render the 404 error page instead of failing the same way.
#170975e340d7 Thanks @iseraph-dev! - Fixes a bug where the advanced routing astro/hono / astro/fetchmiddleware() handler returned the host framework’s default Internal Server Error response instead of rendering the custom 500.astro page when middleware threw. Unmatched requests with a prerendered (or absent) custom 404 page now render the 404 error page instead of failing the same way. Errors surfaced through next (the host framework’s downstream chain) still propagate to the host’s own error handler.
#15819cafec4e Thanks @delucis! - Fixes --port flag being ignored after a Vite-triggered server restart (e.g. when a .env file changes)
#17104b074a37 Thanks @iseraph-dev! - Fixes the custom 500.astro page receiving an empty error prop when the error originated in middleware.
#1707804547ec Thanks @astrobot-houston! - Fixes a spurious Astro.request.headers warning on prerendered pages when security.allowedDomains is configured. The internal allowedDomains header validation now skips prerendered routes, since they use synthetic requests with no real headers.
#16603deaaf3f Thanks @alexanderniebuhr! - Removes the warning that Astro does not support vite v8, since Astro v7 does support vite v8
Cache providers now receive the incoming Request as a second argument to setHeaders(options, request). This allows CDN providers to read the request URL, headers, and other properties when generating cache response headers, for example to auto-tag responses with their pathname for path-based invalidation.
#17098637a1b6 Thanks @matthewp! - Fixes internal Astro headers leaking from direct pages() handler responses
#17116f95e58e Thanks @ascorbic! - Stabilizes route caching, removing the experimental.cache and experimental.routeRules flags and replacing them with the top-level cache and routeRules configuration options.
Route caching, introduced experimentally in v6.0.0, is now stable. It gives you a platform-agnostic way to cache responses from on-demand rendered pages and endpoints, based on standard HTTP caching semantics.
Update your config to move cache and routeRules out of the experimental block:
astro.config.mjs
import { defineConfig, memoryCache } from 'astro/config';
export default defineConfig({
experimental: {
cache: {
provider: memoryCache(),
},
routeRules: {
'/blog/[...path]': { maxAge: 300, swr: 60 },
},
},
cache: {
provider: memoryCache(),
},
routeRules: {
'/blog/[...path]': { maxAge: 300, swr: 60 },
},
});
Set caching directives in your routes with Astro.cache (in .astro pages) or context.cache (in API routes and middleware), and Astro translates them into the appropriate headers or runtime behavior depending on your configured cache provider. You can also define cache rules for routes declaratively in your config using routeRules, without modifying route code.
Astro now strips whitespace from your HTML using JSX rules by default, the same way frameworks like React do. Whitespace and line breaks around elements are removed, but meaningful whitespace within a single line — like a space between two inline elements — is preserved. To keep a space that would otherwise be removed, write it explicitly in your source, for example with {" "}.
This can change rendered output where whitespace between inline elements was previously meaningful. To keep Astro’s earlier behavior, set compressHTML: true for HTML-aware compression, or compressHTML: false to preserve all whitespace.
#17095e84ebc0 Thanks @matthewp! - Improves build performance by removing an unfiltered transform hook from the astro:head-metadata-build plugin. Head propagation modules are now identified by their module ID (?astroPropagatedAssets) instead of scanning every module’s source code.
#170414c4a91c Thanks @iseraph-dev! - Fixes a bug where the advanced routing astro/hono / astro/fetchpages() handler returned the host framework’s default Internal Server Error response instead of rendering the custom 500.astro page when a page threw during render. Unmatched requests with a prerendered (or absent) custom 404 page now render the 404 error page instead of failing the same way.
#170975e340d7 Thanks @iseraph-dev! - Fixes a bug where the advanced routing astro/hono / astro/fetchmiddleware() handler returned the host framework’s default Internal Server Error response instead of rendering the custom 500.astro page when middleware threw. Unmatched requests with a prerendered (or absent) custom 404 page now render the 404 error page instead of failing the same way. Errors surfaced through next (the host framework’s downstream chain) still propagate to the host’s own error handler.
#17104b074a37 Thanks @iseraph-dev! - Fixes the custom 500.astro page receiving an empty error prop when the error originated in middleware.
#17098637a1b6 Thanks @matthewp! - Fixes internal Astro headers leaking from direct pages() handler responses
Astro now renders .md files with satteri() from @astrojs/markdown-satteri, its native Markdown pipeline, instead of the remark/rehype pipeline. @astrojs/markdown-remark is no longer installed by default.
To keep using the remark/rehype pipeline, install @astrojs/markdown-remark and set it as your processor:
The deprecated markdown.remarkPlugins, markdown.rehypePlugins, and markdown.remarkRehype options still work, but now require @astrojs/markdown-remark to be used.
🐞 Patch Changes
#1707804547ec Thanks @astrobot-houston! - Fixes a spurious Astro.request.headers warning on prerendered pages when security.allowedDomains is configured. The internal allowedDomains header validation now skips prerendered routes, since they use synthetic requests with no real headers.
#17035197e50e Thanks @astrobot-houston! - Fixes getRelativeLocaleUrl, getAbsoluteLocaleUrl, and getAbsoluteLocaleUrlList to strip trailing slashes when trailingSlash: 'never' is configured
Previously, any URL containing a double-encoded character (like %255B, which is [ encoded twice) was unconditionally rejected with a 400 Bad Request before middleware or route handlers could run. This broke embedded tools like Sanity Studio whose client-side router legitimately produces double-encoded URLs.
The fix replaces the rejection approach with iterative decoding — multi-level percent-encoding is now fully resolved to its canonical form before being passed to middleware and route matching. This preserves the security fix for CVE-2025-66202 (middleware authorization bypass via double encoding) because middleware now always sees the fully decoded path, making bypass impossible. For example, /api/%2561dmin is decoded to /api/admin, which middleware can correctly block.
#170662f4d92a Thanks @matthewp! - Fixes prerendered redirect targets being incorrectly bundled into the SSR function in hybrid mode, causing massive bundle size inflation
#16882621beb7 Thanks @jettwayio! - fix(render): honour compressHTML when joining head elements
#168928d753b0 Thanks @astrobot-houston! - Fixes custom elements in MDX having their children’s slot attribute stripped by the JSX runtime
When custom elements (tags with hyphens like <my-element>) are used in MDX files, the slot HTML attribute on their children is now correctly preserved. Previously, the shared JSX runtime would treat slot as an Astro slot assignment and remove it from the output, breaking Shadow DOM named slot distribution for web components.
#16957544ee76 Thanks @thelazylamaGit! - Fixes stale inline CSS in server-rendered HTML after CSS file edits during dev
When editing a CSS file (.css, .scss, etc.) during development, the inline <style> tags in server-rendered HTML would retain old CSS content instead of updating. This caused a brief flash of old CSS (FOUC) on fresh page loads before Vite’s client-side HMR corrected the styles.
The fix ensures that Astro’s per-route dev CSS virtual modules are invalidated in both the SSR module graph and the module runner’s evaluation cache when a style file changes, so the next page render picks up the fresh CSS.
#170442220d22 Thanks @astrobot-houston! - Fixes CSS from client:only islands leaking to unrelated pages when Rollup bundles non-CSS-importing modules into the same chunk as CSS-importing modules
#170407c4763d Thanks @astrobot-houston! - Fixes HMR not triggering for files inside the src/middleware/ directory during dev
#1667252fc862 Thanks @martinheidegger! - Fixes support for numeric IDs in YAML frontmatter when using content collection references
#167629de80ae Thanks @alexanderdombroski! - Adds a JSON schema to the Wrangler configuration file generated when running astro add cloudflare
#17046ef771ec Thanks @ematipico! - Improves the diagnostics emitted when Astro parses incorrect .astro files.
#16765b10e86e Thanks @fkatsuhiro! - Fixes an issue where renaming an image file while the dev server is running triggers a build error. Now Astro correctly hot-reloads the image without crashing.
#17026add3df1 Thanks @matthewp! - Hardens addAttribute to drop attribute names containing characters that are invalid per the HTML spec (", ', >, /, =, whitespace)
#17033ffda27b Thanks @matthewp! - Validates the request origin against allowedDomains before fetching prerendered error pages. When allowedDomains is configured and the Host header matches, the original origin is used. Otherwise, the fetch falls back to localhost.