Skip to content

AstroEco is Releasing…

Display your GitHub releases using astro-loader-github-releases

withastro/astro

Patch Changes

  • #15870 920f10b Thanks @matthewp! - Prebundle astro/toolbar in dev when custom dev toolbar apps are registered, preventing re-optimization reloads that can hide or break the toolbar.

  • #15876 f47ac53 Thanks @ematipico! - Fixes redirectToDefaultLocale producing a protocol-relative URL (//locale) instead of an absolute path (/locale) when base is '/'.

  • #15767 e0042f7 Thanks @matthewp! - Fixes server islands (server:defer) not working when only used in prerendered pages with output: 'server'.

  • #15873 35841ed Thanks @matthewp! - Fix a dev server bug where newly created pages could miss layout-imported CSS until restart.

  • #15874 ce0669d Thanks @ematipico! - Fixes a warning when using prefetchAll

  • #15754 58f1d63 Thanks @rururux! - Fixes a bug where a directory at the project root sharing the same name as a page route would cause the dev server to return a 404 instead of serving the page.

  • #15869 76b3a5e Thanks @matthewp! - Update the unknown file extension error hint to recommend vite.resolve.noExternal, which is the correct Vite 7 config key.

withastro/astro

Patch Changes

  • #15815 d1872ee Thanks @matthewp! - Prebundle additional Astro runtime dependencies for Cloudflare development server, speeding up initial start time and preventing required restarts.

  • #15872 3b47b89 Thanks @Princesseuh! - Fixes images not working in dev mode when using the cloudflare option

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.1
withastro/astro

Patch Changes

  • #15868 bb2b8f5 Thanks @ematipico! - Fixes an issue where the adapter would cause a series of warnings during the build.

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.1
withastro/astro

Patch Changes

  • #15868 bb2b8f5 Thanks @ematipico! - Fixes an issue where the adapter would cause a series of warnings during the build.
withastro/starlight

Patch Changes

  • #3751 fb955ff Thanks @pyxelr! - Fixes a regression causing global tableOfContents config to be ignored
withastro/astro

Patch Changes

  • #15711 b2bd27b Thanks @OliverSpeir! - Improves Astro core's dev environment handling for prerendered routes by ensuring route/CSS updates and prerender middleware behavior work correctly across both SSR and prerender environments.

    This enables integrations that use Astro's prerender dev environment (such as Cloudflare with prerenderEnvironment: 'node') to get consistent route matching and HMR behavior during development.

  • #15852 1cdaf9f Thanks @ematipico! - Fixes a regression where the the routes emitted by the astro:build:done hook didn't have the distURL array correctly populated.

  • #15765 ca76ff1 Thanks @matthewp! - Hardens server island POST endpoint validation to use own-property checks for improved consistency

withastro/astro

Minor Changes

  • #15711 b2bd27b Thanks @OliverSpeir! - Adds a prerenderEnvironment option to the Cloudflare adapter.

    By default, Cloudflare uses its workerd runtime for prerendering static pages. Set prerenderEnvironment to 'node' to use Astro's built-in Node.js prerender environment instead, giving prerendered pages access to the full Node.js ecosystem during both build and dev. This is useful when your prerendered pages depend on Node.js-specific APIs or NPM packages that aren't compatible with workerd.

    // astro.config.mjs
    import cloudflare from '@astrojs/cloudflare';
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      adapter: cloudflare({
        prerenderEnvironment: 'node',
      }),
    });

Patch Changes

  • #15845 50fcc8b Thanks @aqiray! - fix: show actionable error when running astro preview without prior build

  • #15794 d1ac58e Thanks @OliverSpeir! - Fixes image serving in passthrough mode by using the Cloudflare ASSETS binding instead of generic fetch, which does not work in Workers for local assets

  • #15850 660da74 Thanks @tristanbes! - fix(cloudflare): forward configPath and other PluginConfig options to the Cloudflare Vite Plugin

    Options like configPath, inspectorPort, persistState, remoteBindings, and auxiliaryWorkers were accepted by the type system but never forwarded to cfVitePlugin(), making them silently ignored.

    Also fixes addWatchFile for configPath which resolved the path relative to the adapter's node_modules directory instead of the project root.

  • #15843 fcd237d Thanks @Calvin-LL! - fix cloudflare image transform ignoring quality parameter

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.1
withastro/starlight

Minor Changes

  • #3644 0d2e7ed Thanks @HiDeoo! - ⚠️ BREAKING CHANGE: The minimum supported version of Starlight is now 0.38.0

    Please use the @astrojs/upgrade command to upgrade your project:

    npx @astrojs/upgrade
withastro/starlight

Minor Changes

  • #3644 0d2e7ed Thanks @HiDeoo! - ⚠️ BREAKING CHANGE: The minimum supported version of Starlight is now 0.38.0

    Please use the @astrojs/upgrade command to upgrade your project:

    npx @astrojs/upgrade
withastro/starlight

Minor Changes

  • #3644 0d2e7ed Thanks @HiDeoo! - Adds support for Astro v6, drops support for Astro v5.

    Upgrade Astro and dependencies

    ⚠️ BREAKING CHANGE: Astro v5 is no longer supported. Make sure you update Astro and any other official integrations at the same time as updating Starlight:

    npx @astrojs/upgrade

    Community Starlight plugins and Astro integrations may also need to be manually updated to work with Astro v6. If you encounter any issues, please reach out to the plugin or integration author to see if it is a known issue or if an updated version is being worked on.

    Update your collections

    ⚠️ BREAKING CHANGE: Drops support for content collections backwards compatibility.

    In Astro 5.x, projects could delay upgrading to the new Content Layer API introduced for content collections because of some existing automatic backwards compatibility that was not previously behind a flag. This meant that it was possible to upgrade from Astro 4 to Astro 5 without updating your content collections, even if you had not enabled the legacy.collections flag. Projects would continue to build, and no errors or warnings would be displayed.

    Astro v6.0 now removes this automatic legacy content collections support, along with the legacy.collections flag.

    If you experience content collections errors after updating to v6, check your project for any removed legacy features that may need updating to the Content Layer API. See the Starlight v0.30.0 upgrade guide for detailed instructions on upgrading legacy collections to the new Content Layer API.

    If you are unable to make any changes to your collections at this time, including Starlight's default docs and i18n collections, you can enable the legacy.collectionsBackwardsCompat flag to upgrade to v6 without updating your collections. This temporary flag preserves some legacy v4 content collections features, and will allow you to keep your collections in their current state until the legacy flag is no longer supported.

  • #3704 375edcc Thanks @florian-lefebvre! - Fixes autocomplete for components exported from @astrojs/starlight/components/*

    ⚠️ Potentially breaking change: This change moves some files used in Starlight’s component internals out of the components/ directory. Direct use of these files was not and is not officially supported. If you previously imported TableOfContents/starlight-toc.ts, TableOfContents/TableOfContentsList.astro, Icons.ts, or SidebarPersistState.ts, please review your code when updating.

  • #3729 3642625 Thanks @delucis! - Improves Starlight’s default body font stack to better support languages such as Chinese, Japanese, and Korean on Windows.
    For most users there should be no visible change.

    If you would prefer to keep the previous font stack, you can add the following custom CSS to your site:

    :root {
      --sl-font-system: ui-sans-serif, system-ui, 'Segoe UI', Roboto,
        'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
        'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
    }
  • #3598 fff38d5 Thanks @HiDeoo! - Makes hover styles consistent in Starlight’s navigation bar

    Previously, the social icon links and language/theme switchers in Starlight’s navigation bar, dimmed on hover.
    After this change, they now increase in contrast on hover instead.
    This matches hover behavior elsewhere, for example in the sidebar, table of contents, or search button.

    ⚠️ Potentially breaking change: this is a subtle change to the hover style colors.
    If you want to preserve the previous styling, you can add the following custom CSS to your site:

    starlight-theme-select label,
    starlight-lang-select label {
      color: var(--sl-color-gray-1);
    
      &:hover {
        color: var(--sl-color-white);
      }
    }
    
    .social-icons a:hover {
      color: var(--sl-color-text-accent);
      opacity: 0.66;
    }
withastro/starlight

Major Changes

  • #3644 0d2e7ed Thanks @HiDeoo! - ⚠️ BREAKING CHANGE: The minimum supported version of Starlight is now 0.38.0

    Please use the @astrojs/upgrade command to upgrade your project:

    npx @astrojs/upgrade
withastro/astro

Patch Changes

  • #15832 95e12a2 Thanks @Princesseuh! - Fixes return; syntax not working in the frontmatter correctly in certain contexts

  • #15803 e42b015 Thanks @merlinnot! - Fixes the Cloudflare adapter adding a SESSION KV binding even when sessions are explicitly configured to use a different driver, such as unstorage/drivers/null.

  • Updated dependencies []:

    • @astrojs/underscore-redirects@1.0.1
withastro/astro

Patch Changes

withastro/astro

Patch Changes

withastro/astro

Patch Changes

withastro/astro

Patch Changes

withastro/astro

Patch Changes

  • #15827 a4c0d0b Thanks @matthewp! - Fixes astro add so the tsconfig preview shows the actual pending changes before confirmation
withastro/astro

Patch Changes

  • Updated dependencies [c2cd371]:
    • @astrojs/internal-helpers@0.7.6
    • @astrojs/underscore-redirects@1.0.0
withastro/astro

Patch Changes

  • Updated dependencies [c2cd371]:
    • @astrojs/internal-helpers@0.7.6
withastro/astro

Patch Changes

  • #15828 c2cd371 Thanks @Princesseuh! - Fixes glob matching of remote patterns matching more paths than intended in select situations
withastro/astro

Patch Changes

  • Updated dependencies [c2cd371]:
    • @astrojs/internal-helpers@0.7.6
withastro/astro

Patch Changes

  • Updated dependencies [c2cd371]:
    • @astrojs/internal-helpers@0.7.6
withastro/astro

Patch Changes

  • Updated dependencies [c2cd371]:
    • @astrojs/internal-helpers@0.7.6
    • @astrojs/markdown-remark@6.3.11
withastro/astro

Patch Changes

  • Updated dependencies []:
    • @astrojs/markdown-remark@6.3.11
withastro/astro

Patch Changes

  • Updated dependencies [c2cd371]:
    • @astrojs/internal-helpers@0.7.6
    • @astrojs/underscore-redirects@1.0.0
withastro/astro

Major Changes

Minor Changes

Patch Changes

withastro/astro

Minor Changes

Patch Changes

withastro/astro

Major Changes

Patch Changes

withastro/astro

Major Changes

Minor Changes

Patch Changes

withastro/astro

Major Changes

  • #15654 a32aee6 Thanks @florian-lefebvre! - Removes the experimentalErrorPageHost option

    This option allowed fetching a prerendered error page from a different host than the server is currently running on.

    However, there can be security implications with prefetching from other hosts, and often more customization was required to do this safely. This has now been removed as a built-in option so that you can implement your own secure solution as needed and appropriate for your project via middleware.

    What should I do?

    If you were previously using this feature, you must remove the option from your adapter configuration as it no longer exists:

    // astro.config.mjs
    import { defineConfig } from 'astro/config'
    import node from '@astrojs/node'
    
    export default defineConfig({
      adapter: node({
        mode: 'standalone',
    -    experimentalErrorPageHost: 'http://localhost:4321'
      })
    })

    You can replicate the previous behavior by checking the response status in a middleware and fetching the prerendered page yourself:

    // src/middleware.ts
    import { defineMiddleware } from 'astro:middleware';
    
    export const onRequest = defineMiddleware(async (ctx, next) => {
      const response = await next();
      if (response.status === 404 || response.status === 500) {
        return fetch(`http://localhost:4321/${response.status}.html`);
      }
      return response;
    });

Minor Changes

  • #15258 d339a18 Thanks @ematipico! - Stabilizes the adapter feature experimentalStatiHeaders. If you were using this feature in any of the supported adapters, you'll need to change the name of the flag:

    export default defineConfig({
      adapter: netlify({
    -    experimentalStaticHeaders: true
    +    staticHeaders: true
      })
    })
  • #15759 39ff2a5 Thanks @matthewp! - Adds a new bodySizeLimit option to the @astrojs/node adapter

    You can now configure a maximum allowed request body size for your Node.js standalone server. The default limit is 1 GB. Set the value in bytes, or pass 0 to disable the limit entirely:

    import node from '@astrojs/node';
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      adapter: node({
        mode: 'standalone',
        bodySizeLimit: 1024 * 1024 * 100, // 100 MB
      }),
    });
  • #15006 f361730 Thanks @florian-lefebvre! - Adds new session driver object shape

    For greater flexibility and improved consistency with other Astro code, session drivers are now specified as an object:

    -import { defineConfig } from 'astro/config'
    +import { defineConfig, sessionDrivers } from 'astro/config'
    
    export default defineConfig({
      session: {
    -    driver: 'redis',
    -    options: {
    -      url: process.env.REDIS_URL
    -    },
    +    driver: sessionDrivers.redis({
    +      url: process.env.REDIS_URL
    +    }),
      }
    })

    Specifying the session driver as a string has been deprecated, but will continue to work until this feature is removed completely in a future major version. The object shape is the current recommended and documented way to configure a session driver.

  • #14946 95c40f7 Thanks @ematipico! - Removes the experimental.csp flag and replaces it with a new configuration option security.csp - (v6 upgrade guidance)

Patch Changes

  • #15473 d653b86 Thanks @matthewp! - Improves error page loading to read from disk first before falling back to configured host

  • #15562 e14a51d Thanks @florian-lefebvre! - Updates to new Adapter API introduced in v6

  • #15585 98ea30c Thanks @matthewp! - Add a default body size limit for server actions to prevent oversized requests from exhausting memory.

  • #15777 02e24d9 Thanks @matthewp! - Fixes CSRF origin check mismatch by passing the actual server listening port to createRequest, ensuring the constructed URL origin includes the correct port (e.g., http://localhost:4321 instead of http://localhost). Also restricts X-Forwarded-Proto to only be trusted when allowedDomains is configured.

  • #15714 9a2c949 Thanks @ematipico! - Fixes an issue where static headers weren't correctly applied when the website uses base.

  • #15763 1567e8c Thanks @matthewp! - Normalizes static file paths before evaluating dotfile access rules for improved consistency

  • #15164 54dc11d Thanks @HiDeoo! - Fixes an issue where the Node.js adapter could fail to serve a 404 page matching a pre-rendered dynamic route pattern.

  • #15745 20b05c0 Thanks @matthewp! - Hardens static file handler path resolution to ensure resolved paths stay within the client directory

  • #15495 5b99e90 Thanks @leekeh! - Refactors to use middlewareMode adapter feature (set to classic)

  • #15657 cb625b6 Thanks @qzio! - Adds a new security.actionBodySizeLimit option to configure the maximum size of Astro Actions request bodies.

    This lets you increase the default 1 MB limit when your actions need to accept larger payloads. For example, actions that handle file uploads or large JSON payloads can now opt in to a higher limit.

    If you do not set this option, Astro continues to enforce the 1 MB default to help prevent abuse.

    // astro.config.mjs
    export default defineConfig({
      security: {
        actionBodySizeLimit: 10 * 1024 * 1024, // set to 10 MB
      },
    });
  • Updated dependencies [4ebc1e3, 4e7f3e8, a164c77, cf6ea6b, a18d727, 240c317, 745e632]:

    • @astrojs/internal-helpers@0.8.0
withastro/astro

Major Changes

Minor Changes

  • #15258 d339a18 Thanks @ematipico! - Stabilizes the adapter feature experimentalStatiHeaders. If you were using this feature in any of the supported adapters, you'll need to change the name of the flag:

    export default defineConfig({
      adapter: netlify({
    -    experimentalStaticHeaders: true
    +    staticHeaders: true
      })
    })
  • #15809 94b4a46 Thanks @Princesseuh! - Adds support for the fit option to the image service

  • #15495 5b99e90 Thanks @leekeh! - Adds new middlewareMode adapter feature and deprecates edgeMiddleware option

    The edgeMiddleware option is now deprecated and will be removed in a future major release, so users should transition to using the new middlewareMode feature as soon as possible.

    export default defineConfig({
      adapter: netlify({
    -    edgeMiddleware: true
    +    middlewareMode: 'edge'
      })
    })
  • #15006 f361730 Thanks @florian-lefebvre! - Adds new session driver object shape

    For greater flexibility and improved consistency with other Astro code, session drivers are now specified as an object:

    -import { defineConfig } from 'astro/config'
    +import { defineConfig, sessionDrivers } from 'astro/config'
    
    export default defineConfig({
      session: {
    -    driver: 'redis',
    -    options: {
    -      url: process.env.REDIS_URL
    -    },
    +    driver: sessionDrivers.redis({
    +      url: process.env.REDIS_URL
    +    }),
      }
    })

    Specifying the session driver as a string has been deprecated, but will continue to work until this feature is removed completely in a future major version. The object shape is the current recommended and documented way to configure a session driver.

  • #15413 736216b Thanks @florian-lefebvre! - Updates the implementation to use the new Adapter API

  • #14946 95c40f7 Thanks @ematipico! - Removes the experimental.csp flag and replaces it with a new configuration option security.csp - (v6 upgrade guidance)

Patch Changes

  • #15187 bbb5811 Thanks @matthewp! - Update to Astro 6 beta

  • #15781 2de969d Thanks @ematipico! - Adds a new clientAddress option to the createContext() function

    Providing this value gives adapter and middleware authors explicit control over the client IP address. When not provided, accessing clientAddress throws an error consistent with other contexts where it is not set by the adapter.

    Additionally, both of the official Netlify and Vercel adapters have been updated to provide this information in their edge middleware.

    import { createContext } from 'astro/middleware';
    
    createContext({
      clientAddress: context.headers.get('x-real-ip'),
    });
  • #15665 52a7efd Thanks @matthewp! - Fixes builds that were failing with "Entry module cannot be external" error when using the Netlify adapter

    This error was preventing sites from building after recent internal changes. Your builds should now work as expected without any changes to your code.

  • #15679 19ba822 Thanks @matthewp! - Fixes server-rendered routes returning 404 errors

    A configuration error in the build output prevented Netlify from correctly routing requests to server-rendered pages, causing them to return 404 errors. This fix ensures that all server routes are properly handled by the Netlify SSR function.

  • #15809 94b4a46 Thanks @Princesseuh! - Fixes the image CDN being used in development despite being disabled in certain cases

  • #15460 ee7e53f Thanks @florian-lefebvre! - Updates to use the new Adapter API

  • #15450 50c9129 Thanks @florian-lefebvre! - Fixes a case where build.serverEntry would not be respected when using the new Adapter API

  • #15461 9f21b24 Thanks @florian-lefebvre! - Updates to new Adapter API introduced in v6

  • Updated dependencies [4ebc1e3, 4e7f3e8, a164c77, cf6ea6b, a18d727, 240c317, 745e632]:

    • @astrojs/internal-helpers@0.8.0
    • @astrojs/underscore-redirects@1.0.0
withastro/astro

Patch Changes

withastro/astro

Major Changes

  • #14306 141c4a2 Thanks @ematipico! - Changes the API for creating a custom entrypoint, replacing the createExports() function with a direct export pattern.

    What should I do?

    If you're using a custom entryPoint in your Cloudflare adapter config, update your existing worker file that uses createExports() to reflect the new, simplified pattern:

    my-entry.ts

    import type { SSRManifest } from 'astro';
    import { App } from 'astro/app';
    import { handle } from '@astrojs/cloudflare/handler';
    import { DurableObject } from 'cloudflare:workers';
    
    class MyDurableObject extends DurableObject<Env> {
      constructor(ctx: DurableObjectState, env: Env) {
        super(ctx, env);
      }
    }
    
    export function createExports(manifest: SSRManifest) {
      const app = new App(manifest);
      return {
        default: {
          async fetch(request, env, ctx) {
            await env.MY_QUEUE.send('log');
            return handle(manifest, app, request, env, ctx);
          },
          async queue(batch, _env) {
            let messages = JSON.stringify(batch.messages);
            console.log(`consumed from our queue: ${messages}`);
          },
        } satisfies ExportedHandler<Env>,
        MyDurableObject: MyDurableObject,
      };
    }

    To create the same custom entrypoint using the updated API, export the following function instead:

    my-entry.ts

    import { handle } from '@astrojs/cloudflare/utils/handler';
    
    export default {
      async fetch(request, env, ctx) {
        await env.MY_QUEUE.send("log");
        return handle(manifest, app, request, env, ctx);
      },
      async queue(batch, _env) {
        let messages = JSON.stringify(batch.messages);
        console.log(`consumed from our queue: ${messages}`);
      }
    } satisfies ExportedHandler<Env>,

    The manifest is now created internally by the adapter.

  • #15435 957b9fe Thanks @rururux! - Changes the default image service from compile to cloudflare-binding. Image services options that resulted in broken images in development due to Node JS incompatiblities have now been updated to use the noop passthrough image service in dev mode. - (Cloudflare v13 and Astro6 upgrade guidance)

  • #15400 41eb284 Thanks @florian-lefebvre! - Removes the workerEntryPoint option, which wasn't used anymore. Set the main field of your wrangler config instead

    See how to migrate

  • #14306 141c4a2 Thanks @ematipico! - Development server now runs in workerd

    astro dev now runs your Cloudflare application using Cloudflare's workerd runtime instead of Node.js. This means your development environment is now a near-exact replica of your production environment—the same JavaScript engine, the same APIs, the same behavior. You'll catch issues during development that would have only appeared in production, and features like Durable Objects, Workers Analytics Engine, and R2 bindings work exactly as they do on Cloudflare's platform.

    New runtime

    Previously, Astro.locals.runtime provided access to Cloudflare-specific APIs. These APIs have now moved to align with Cloudflare's native patterns.

    What should I do?

    Update occurrences of Astro.locals.runtime:

    • Astro.locals.runtime.env → Import env from cloudflare:workers
    • Astro.locals.runtime.cf → Access via Astro.request.cf
    • Astro.locals.runtime.caches → Use the global caches object
    • Astro.locals.runtime (for ExecutionContext) → Use Astro.locals.cfContext

    Here's an example showing how to update your code:

    Before:

    ---
    const { env, cf, caches, ctx } = Astro.locals.runtime;
    const value = await env.MY_KV.get('key');
    const country = cf.country;
    await caches.default.put(request, response);
    ctx.waitUntil(promise);
    ---
    
    <h1>Country: {country}</h1>

    After:

    ---
    import { env } from 'cloudflare:workers';
    
    const value = await env.MY_KV.get('key');
    const country = Astro.request.cf.country;
    await caches.default.put(request, response);
    Astro.locals.cfContext.waitUntil(promise);
    ---
    
    <h1>Country: {country}</h1>
  • #15345 840fbf9 Thanks @matthewp! - Removes the cloudflareModules adapter option

    The cloudflareModules option has been removed because it is no longer necessary. Cloudflare natively supports importing .sql, .wasm, and other module types.

    What should I do?

    Remove the cloudflareModules option from your Cloudflare adapter configuration if you were using it:

    import cloudflare from '@astrojs/cloudflare';
    
    export default defineConfig({
      adapter: cloudflare({
    -   cloudflareModules: true
      })
    });
  • #14445 ecb0b98 Thanks @florian-lefebvre! - Astro v6.0 upgrades to Vite v7.0 as the development server and production bundler - (v6 upgrade guidance)

  • #15037 8641805 Thanks @matthewp! - Updates the Wrangler entrypoint

    Previously, the main field in wrangler.jsonc pointed to the built output, since Wrangler only ran in production after the build completed:

    {
      "main": "dist/_worker.js/index.js",
    }

    Now that Wrangler runs in both development (via workerd) and production, Astro provides a default entrypoint that works for both scenarios.

    What should I do?

    Update your wrangler.jsonc to use the new entrypoint:

    {
      "main": "@astrojs/cloudflare/entrypoints/server",
    }

    This single entrypoint handles both astro dev and production deployments.

  • #15480 e118214 Thanks @alexanderniebuhr! - Drops official support for Cloudflare Pages in favor of Cloudflare Workers

    The Astro Cloudflare adapter now only supports deployment to Cloudflare Workers by default in order to comply with Cloudflare's recommendations for new projects. If you are currently deploying to Cloudflare Pages, consider migrating to Workers by following the Cloudflare guide for an optimal experience and full feature support.

Minor Changes

  • #15435 957b9fe Thanks @rururux! - Adds support for configuring the image service as an object with separate build and runtime options

    It is now possible to set both a build-time and runtime service independently. Currently, 'compile' is the only available build time option. The supported runtime options are 'passthrough' (default) and 'cloudflare-binding':

    import { defineConfig } from 'astro/config';
    import cloudflare from '@astrojs/cloudflare';
    
    export default defineConfig({
      adapter: cloudflare({
        imageService: { build: 'compile', runtime: 'cloudflare-binding' },
      }),
    });

    See the Cloudflare adapter imageService docs for more information about configuring your image service.

  • #15077 a164c77 Thanks @matthewp! - Adds support for prerendering pages using the workerd runtime.

    The Cloudflare adapter now uses the new setPrerenderer() API to prerender pages via HTTP requests to a local preview server running workerd, instead of using Node.js. This ensures prerendered pages are built using the same runtime that serves them in production.

  • #14306 141c4a2 Thanks @ematipico! - Adds support for astro preview command

    Developers can now use astro preview to test their Cloudflare Workers application locally before deploying. The preview runs using Cloudflare's workerd runtime, giving you a staging environment that matches production exactly—including support for KV namespaces, environment variables, and other Cloudflare-specific features.

  • #15037 8641805 Thanks @matthewp! - The Wrangler configuration file is now optional. If you don't have custom Cloudflare bindings (KV, D1, Durable Objects, etc.), Astro will automatically generate a default configuration for you.

    What should I do?

    If your wrangler.jsonc only contains basic configuration like this:

    {
      "main": "@astrojs/cloudflare/entrypoints/server",
      "compatibility_date": "2026-01-28",
      "assets": {
        "directory": "./dist",
        "binding": "ASSETS",
      },
    }

    You can safely delete the file. Astro will handle this configuration automatically.

    You only need a wrangler config file if you're using:

    • KV namespaces
    • D1 databases
    • Durable Objects
    • R2 buckets
    • Environment variables
    • Custom compatibility flags
    • Other Cloudflare-specific features
  • #15006 f361730 Thanks @florian-lefebvre! - Adds new session driver object shape

    For greater flexibility and improved consistency with other Astro code, session drivers are now specified as an object:

    -import { defineConfig } from 'astro/config'
    +import { defineConfig, sessionDrivers } from 'astro/config'
    
    export default defineConfig({
      session: {
    -    driver: 'redis',
    -    options: {
    -      url: process.env.REDIS_URL
    -    },
    +    driver: sessionDrivers.redis({
    +      url: process.env.REDIS_URL
    +    }),
      }
    })

    Specifying the session driver as a string has been deprecated, but will continue to work until this feature is removed completely in a future major version. The object shape is the current recommended and documented way to configure a session driver.

  • #15556 8fb329b Thanks @florian-lefebvre! - Adds support for more @cloudflare/vite-plugin options

    The adapter now accepts the following options from Cloudflare's Vite plugin:

    • auxiliaryWorkers
    • configPath
    • inspectorPort
    • persistState
    • remoteBindings
    • experimental.headersAndRedirectsDevModeSupport

    For example, you can now set inspectorPort to provide a custom port for debugging your Workers:

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    import cloudflare from '@astrojs/cloudflare';
    
    export default defineConfig({
      adapter: cloudflare({
        inspectorPort: 3456,
      }),
    });

Patch Changes

  • #15044 7cac71b Thanks @florian-lefebvre! - Removes an exposed internal API of the preview server

  • #15080 f67b738 Thanks @gameroman! - Updates wrangler dependency to be a peerDependency over a dependency

  • #15039 6cc96e7 Thanks @matthewp! - Fixes static content deployment by moving it to another folder, so Wrangler can tell the static and worker content apart

  • #15452 e1aa3f3 Thanks @matthewp! - Fixes server-side dependencies not being discovered ahead of time during development

    Previously, imports in .astro file frontmatter were not scanned by Vite's dependency optimizer, causing a "new dependencies optimized" message and page reload when the dependency was first encountered. Astro is now able to scan these dependencies ahead of time.

  • #15391 5d996cc Thanks @florian-lefebvre! - Fixes types of the handle() function exported from /handler, that could be incompatible with types generated by wrangler types

  • #15696 a9fd221 Thanks @Princesseuh! - Fixes duplicate logging showing up in some cases when prerendering pages

  • #15309 4b9c8b8 Thanks @ematipico! - Update the underneath @cloudflare/workers-types library to address a warning emitted by the package manager during the installation.

  • #15079 4463a55 Thanks @ascorbic! - Fixes auto-provisioning of default bindings (SESSION KV, IMAGES, and ASSETS). Default bindings are now correctly applied whether or not you have a wrangler.json file.
    Previously, these bindings were only added when no wrangler config file existed. Now they are added in both cases, unless you've already defined them yourself.

  • #15694 66449c9 Thanks @matthewp! - Fixes deployment of static sites with the Cloudflare adapter

    Fixes an issue with detecting and building fully static sites that caused deployment errors when using output: 'static' with the Cloudflare adapter

  • #15565 30cd6db Thanks @ematipico! - Fixes an issue where the use of the Code component would result in an unexpected error.

  • #15121 06261e0 Thanks @ematipico! - Fixes a bug where the Astro, with the Cloudflare integration, couldn't correctly serve certain routes in the development server.

  • #15026 90c608c Thanks @matthewp! - Improves prebundling of internal Astro modules

  • #15778 4ebc1e3 Thanks @ematipico! - Fixes an issue where the computed clientAddress was incorrect in cases of a Request header with multiple values. The clientAddress is now also validated to contain only characters valid in IP addresses, rejecting injection payloads.

  • #15669 d5a888b Thanks @florian-lefebvre! - Removes the cssesc dependency

    This CommonJS dependency could sometimes cause errors because Astro is ESM-only. It is now replaced with a built-in ESM-friendly implementation.

  • #15075 ee2c260 Thanks @matthewp! - Adds deprecation errors for Astro.locals.runtime properties to help migrate from Astro v5 to v6

    When accessing the removed Astro.locals.runtime properties on Cloudflare, developers now receive clear error messages explaining the migration path:

    • Astro.locals.runtime.env → Use import { env } from "cloudflare:workers"
    • Astro.locals.runtime.cf → Use Astro.request.cf
    • Astro.locals.runtime.caches → Use the global caches object
    • Astro.locals.runtime.ctx → Use Astro.locals.cfContext
  • #15336 9cce92e Thanks @ascorbic! - Fixes a dev server issue where framework components from linked packages would fail to load with a 504 error.

    This could occur when using client:only or other client directives with components from monorepo packages (linked via file: or workspace protocol). The first request would trigger Vite's dependency optimizer mid-request, causing concurrent client module requests to fail.

  • #15255 a66783a Thanks @florian-lefebvre! - Fixes a case where the types of handle() could mismatch with the ones from the user's project. They now rely on globals, that can be obtained by running wrangler types

  • #15045 31074fc Thanks @ematipico! - Fixes an issue where using the Vue integration with the Cloudflare adapter resulted in some runtime errors.

  • #15386 a0234a3 Thanks @OliverSpeir! - Updates astro add cloudflare to use the latest valid compatibility_date in the wrangler config, if available

  • #15432 e2ad69e Thanks @OliverSpeir! - Removes unnecessary warning about sharp from being printed at start of dev server and build

  • #15588 425ea16 Thanks @rururux! - Fixes an issue where esbuild would throw a "Top-level return cannot be used inside an ECMAScript module" error during dependency scanning in certain environments.

  • #15450 50c9129 Thanks @florian-lefebvre! - Fixes a case where build.serverEntry would not be respected when using the new Adapter API

  • #15030 b5aa52b Thanks @ematipico! - Fixed an issue where the feature experimental.chromeDevtoolsWorkspace wasn't supported by the new version of the adapter.

  • #15648 802426b Thanks @rururux! - Restore and fix <Code /> component functionality on Cloudflare Workers.

  • #15478 ee519e5 Thanks @matthewp! - Fixes fully static sites to not output server-side worker code. When all routes are prerendered, the _worker.js directory is now removed from the build output.

  • #15636 5ecd04c Thanks @florian-lefebvre! - Adds an error when running on Stackblitz, since workerd doesn't support it

  • #15269 6f82aae Thanks @ematipico! - Fixes a regression where build.serverEntry stopped working as expected.

  • #15798 05771cf Thanks @rururux! - Fixes a regression where using the adapter would throw an error when using an integration that uses JSX.

  • #15053 674b63f Thanks @matthewp! - Excludes astro:* and virtual:astro:* from client optimizeDeps in core. Needed for prefetch users since virtual modules are now in the dependency graph.

  • #15495 5b99e90 Thanks @leekeh! - Refactors to use middlewareMode adapter feature (set to classic)

  • Updated dependencies [4ebc1e3, 4e7f3e8, a164c77, cf6ea6b, a18d727, 240c317, 745e632]:

    • @astrojs/internal-helpers@0.8.0
    • @astrojs/underscore-redirects@1.0.0
withastro/astro

Minor Changes

Patch Changes

withastro/astro

Major Changes

Patch Changes

withastro/astro

Major Changes

Patch Changes

withastro/astro

Minor Changes

  • #15778 4ebc1e3 Thanks @ematipico! - Added a new entry point called /request, which exposes utilities to work with the Request type:

    • getFirstForwardedValue: retrieves the first value of a multi-value header.
    • isValidIpAddress: checks whether a string contains only characters valid in IPv4/IPv6 addresses.
    • getValidatedIpFromHeader: extracts the first value from a header and validates it as an IP address.
    • getClientIpAddress: retrieves and validates the first IP from the x-forwarded-for header.
  • #15077 a164c77 Thanks @matthewp! - Adds normalizePathname() utility function for normalizing URL pathnames to match the canonical form used by route generation.

  • #15419 a18d727 Thanks @ematipico! - Adds a new /cli specifier and the utility NPM_PACKAGE_NAME_REGEX.

  • #15369 240c317 Thanks @florian-lefebvre! - BREAKING CHANGE

    Removes collapseDuplicateSlashes(), startsWithForwardSlash(), startsWithDotDotSlash(), startsWithDotSlash() and isAbsolutePath() from the /path export

  • #15771 745e632 Thanks @rururux! - Adds the new utilities MANY_LEADING_SLASHES and collapseDuplicateLeadingSlashes.

Patch Changes

  • #15700 4e7f3e8 Thanks @ocavue! - Adds a fork of createFilter from @rollup/pluginutils without Node.js APIs.

  • #15779 cf6ea6b Thanks @Princesseuh! - Fixes glob matching of remote patterns matching more paths than intended in select situations

withastro/astro

Major Changes

Patch Changes

  • #15187 bbb5811 Thanks @matthewp! - Update to Astro 6 beta

  • #15344 9d87f77 Thanks @matthewp! - Fixes a hang that could occur when the npm registry is slow or unresponsive by adding a 10 second timeout to the version check

  • #15350 d758b68 Thanks @matthewp! - Errors when --add and --no-install flags are used together, as --add requires dependencies to be installed

  • #15264 11efb05 Thanks @florian-lefebvre! - Lower the Node version requirement to allow running on Stackblitz until it supports v22

  • #15419 a18d727 Thanks @ematipico! - Fixes an issue where --add could accept any kind of string, leading to different errors. Now --add accepts only values of valid integrations and adapters.

  • #15419 a18d727 Thanks @ematipico! - Fixes an issue where the add command could accept any arbitrary value, leading the possible command injections. Now add and --add accepts
    values that are only acceptable npmjs.org names.

withastro/astro

Major Changes

Minor Changes

  • #15277 cb99214 Thanks @ematipico! - Fixes an issue where the function createShikiHighlighter would always create a new Shiki highlighter instance. Now the function returns a cached version of the highlighter based on the Shiki options. This should improve the performance for sites that heavily rely on Shiki and code in their pages.

  • #15332 7c55f80 Thanks @matthewp! - Exposes the fileURL option in MarkdownProcessorRenderOptions, allowing callers to specify the file URL for resolving relative image paths.

Patch Changes

withastro/astro

Major Changes

  • #15413 736216b Thanks @florian-lefebvre! - Removes the deprecated @astrojs/vercel/serverless and @astrojs/vercel/static exports. Use the @astrojs/vercel export instead

Minor Changes

  • #15258 d339a18 Thanks @ematipico! - Stabilizes the adapter feature experimentalStatiHeaders. If you were using this feature in any of the supported adapters, you'll need to change the name of the flag:

    export default defineConfig({
      adapter: netlify({
    -    experimentalStaticHeaders: true
    +    staticHeaders: true
      })
    })
  • #15413 736216b Thanks @florian-lefebvre! - Updates the implementation to use the new Adapter API

  • #15495 5b99e90 Thanks @leekeh! - Adds new middlewareMode adapter feature and deprecates edgeMiddleware option

    The edgeMiddleware option is now deprecated and will be removed in a future release, so users should transition to using the new middlewareMode feature as soon as possible.

    export default defineConfig({
      adapter: vercel({
    -    edgeMiddleware: true
    +    middlewareMode: 'edge'
      })
    })
  • #14946 95c40f7 Thanks @ematipico! - Removes the experimental.csp flag and replaces it with a new configuration option security.csp - (v6 upgrade guidance)

Patch Changes

  • #15781 2de969d Thanks @ematipico! - Adds a new clientAddress option to the createContext() function

    Providing this value gives adapter and middleware authors explicit control over the client IP address. When not provided, accessing clientAddress throws an error consistent with other contexts where it is not set by the adapter.

    Additionally, both of the official Netlify and Vercel adapters have been updated to provide this information in their edge middleware.

    import { createContext } from 'astro/middleware';
    
    createContext({
      clientAddress: context.headers.get('x-real-ip'),
    });
  • #15778 4ebc1e3 Thanks @ematipico! - Fixes an issue where the computed clientAddress was incorrect in cases of a Request header with multiple values. The clientAddress is now also validated to contain only characters valid in IP addresses, rejecting injection payloads.

  • #15460 ee7e53f Thanks @florian-lefebvre! - Updates to use the new Adapter API

  • #15450 50c9129 Thanks @florian-lefebvre! - Fixes a case where build.serverEntry would not be respected when using the new Adapter API

  • #15461 9f21b24 Thanks @florian-lefebvre! - Updates to new Adapter API introduced in v6

  • #15125 6feb0d7 Thanks @florian-lefebvre! - Updates Node versions data to account for v24 as the default

  • Updated dependencies [4ebc1e3, 4e7f3e8, a164c77, cf6ea6b, a18d727, 240c317, 745e632]:

    • @astrojs/internal-helpers@0.8.0
withastro/astro

Major Changes

Patch Changes

withastro/astro

Minor Changes

Patch Changes

  • #15184 f47c071 Thanks @ematipico! - Fixes an issue where the package wasn't correctly published

  • #15457 6e8da44 Thanks @AhmadYasser1! - Fixes custom attributes on Markdoc's built-in {% table %} tag causing "Invalid attribute" validation errors.

    In Markdoc, table exists as both a tag ({% table %}) and a node (the inner table structure). When users defined custom attributes on either nodes.table or tags.table, the attributes weren't synced to the counterpart, causing validation to fail on whichever side was missing the declaration.

    The fix automatically syncs custom attribute declarations between tags and nodes that share the same name, so users can define attributes on either side and have them work correctly.

  • #15264 11efb05 Thanks @florian-lefebvre! - Lower the Node version requirement to allow running on Stackblitz until it supports v22

  • #15335 75931c2 Thanks @matthewp! - Fixes an issue where spreading a built-in Markdoc node config (e.g., ...Markdoc.nodes.fence) and specifying a custom render component would not work because the built-in transform() function was overriding the custom component. Now, render wins over transform when both are specified.

  • Updated dependencies [bbb5811, bbb5811, 4ebc1e3, cb99214, 80f0225, 727b0a2, 11efb05, 4e7f3e8, a164c77, 1fa4177, 7c55f80, cf6ea6b, e131261, 6f19ecc, f94d3c5, a18d727, 240c317, 745e632]:

    • @astrojs/markdown-remark@7.0.0
    • @astrojs/prism@4.0.0
    • @astrojs/internal-helpers@0.8.0
withastro/astro

Major Changes

Minor Changes

  • #15425 0317e99 Thanks @ocavue! - Updates @vitejs/plugin-vue to v6, @vitejs/plugin-vue-jsx to v5, and vite-plugin-vue-devtools to v8. No changes are needed from users.

Patch Changes

withastro/astro

Minor Changes

Patch Changes

withastro/astro

Patch Changes

withastro/astro

Patch Changes

withastro/astro

Patch Changes

  • #15125 6feb0d7 Thanks @florian-lefebvre! - Fix "Find All References" and other TypeScript features by ensuring the plugin bundle is correctly included

  • #15125 6feb0d7 Thanks @florian-lefebvre! - Fixes syntax highlighting sometimes not working when the frontmatter or script tags ended with certain TypeScript constructs

  • #15496 eb7cdda Thanks @matthewp! - Fix syntax highlighting for lowercase component tags that start with "style" or "script".

withastro/astro

Major Changes

Minor Changes

  • #14306 141c4a2 Thanks @ematipico! - Adds new optional properties to setAdapter() for adapter entrypoint handling in the Adapter API

    Changes:

    • New optional properties:
      • entryType?: 'self' | 'legacy-dynamic' - determines if the adapter provides its own entrypoint ('self') or if Astro constructs one ('legacy-dynamic', default)

    Migration: Adapter authors can optionally add these properties to support custom dev entrypoints. If not specified, adapters will use the legacy behavior.

  • #15700 4e7f3e8 Thanks @ocavue! - Updates the internal logic during SSR by providing additional metadata for UI framework integrations.

  • #15231 3928b87 Thanks @rururux! - Adds a new optional getRemoteSize() method to the Image Service API.

    Previously, inferRemoteSize() had a fixed implementation that fetched the entire image to determine its dimensions.
    With this new helper function that extends inferRemoteSize(), you can now override or extend how remote image metadata is retrieved.

    This enables use cases such as:

    • Caching: Storing image dimensions in a database or local cache to avoid redundant network requests.
    • Provider APIs: Using a specific image provider's API (like Cloudinary or Vercel) to get dimensions without downloading the file.

    For example, you can add a simple cache layer to your existing image service:

    const cache = new Map();
    
    const myService = {
      ...baseService,
      async getRemoteSize(url, imageConfig) {
        if (cache.has(url)) return cache.get(url);
    
        const result = await baseService.getRemoteSize(url, imageConfig);
        cache.set(url, result);
        return result;
      },
    };

    See the Image Services API reference documentation for more information.

  • #15077 a164c77 Thanks @matthewp! - Updates the Integration API to add setPrerenderer() to the astro:build:start hook, allowing adapters to provide custom prerendering logic.

    The new API accepts either an AstroPrerenderer object directly, or a factory function that receives the default prerenderer:

    'astro:build:start': ({ setPrerenderer }) => {
      setPrerenderer((defaultPrerenderer) => ({
        name: 'my-prerenderer',
        async setup() {
          // Optional: called once before prerendering starts
        },
        async getStaticPaths() {
          // Returns array of { pathname: string, route: RouteData }
          return defaultPrerenderer.getStaticPaths();
        },
        async render(request, { routeData }) {
          // request: Request
          // routeData: RouteData
          // Returns: Response
        },
        async teardown() {
          // Optional: called after all pages are prerendered
        }
      }));
    }

    Also adds the astro:static-paths virtual module, which exports a StaticPaths class for adapters to collect all prerenderable paths from within their target runtime. This is useful when implementing a custom prerenderer that runs in a non-Node environment:

    // In your adapter's request handler (running in target runtime)
    import { App } from 'astro/app';
    import { StaticPaths } from 'astro:static-paths';
    
    export function createApp(manifest) {
      const app = new App(manifest);
    
      return {
        async fetch(request) {
          const { pathname } = new URL(request.url);
    
          // Expose endpoint for prerenderer to get static paths
          if (pathname === '/__astro_static_paths') {
            const staticPaths = new StaticPaths(app);
            const paths = await staticPaths.getAll();
            return new Response(JSON.stringify({ paths }));
          }
    
          // Normal request handling
          return app.render(request);
        },
      };
    }

    See the adapter reference for more details on implementing a custom prerenderer.

  • #15345 840fbf9 Thanks @matthewp! - Adds a new emitClientAsset function to astro/assets/utils for integration authors. This function allows emitting assets that will be moved to the client directory during SSR builds, useful for assets referenced in server-rendered content that need to be available on the client.

    import { emitClientAsset } from 'astro/assets/utils';
    
    // Inside a Vite plugin's transform or load hook
    const handle = emitClientAsset(this, {
      type: 'asset',
      name: 'my-image.png',
      source: imageBuffer,
    });
  • #15460 ee7e53f Thanks @florian-lefebvre! - Updates the Adapter API to allow providing a serverEntrypoint when using entryType: 'self'

    Astro 6 introduced a new powerful yet simple Adapter API for defining custom server entrypoints. You can now call setAdapter() with the entryType: 'self' option and specify your custom serverEntrypoint:

    export function myAdapter() {
      return {
        name: 'my-adapter',
        hooks: {
          'astro:config:done': ({ setAdapter }) => {
            setAdapter({
              name: 'my-adapter',
              entryType: 'self',
              serverEntrypoint: 'my-adapter/server.js',
              supportedAstroFeatures: {
                // ...
              },
            });
          },
        },
      };
    }

    If you need further customization at the Vite level, you can omit serverEntrypoint and instead specify your custom server entrypoint with vite.build.rollupOptions.input.

  • #15781 2de969d Thanks @ematipico! - Adds a new clientAddress option to the createContext() function

    Providing this value gives adapter and middleware authors explicit control over the client IP address. When not provided, accessing clientAddress throws an error consistent with other contexts where it is not set by the adapter.

    Additionally, both of the official Netlify and Vercel adapters have been updated to provide this information in their edge middleware.

    import { createContext } from 'astro/middleware';
    
    createContext({
      clientAddress: context.headers.get('x-real-ip'),
    });
  • #15258 d339a18 Thanks @ematipico! - Stabilizes the adapter feature experimentalStatiHeaders. If you were using this feature in any of the supported adapters, you'll need to change the name of the flag:

    export default defineConfig({
      adapter: netlify({
    -    experimentalStaticHeaders: true
    +    staticHeaders: true
      })
    })
  • #15535 dfe2e22 Thanks @florian-lefebvre! - Exports new createRequest() and writeResponse() utilities from astro/app/node

    To replace the deprecated NodeApp.createRequest() and NodeApp.writeResponse() methods, the astro/app/node module now exposes new createRequest() and writeResponse() utilities. These can be used to convert a NodeJS IncomingMessage into a web-standard Request and stream a web-standard Response into a NodeJS ServerResponse:

    import { createApp } from 'astro/app/entrypoint';
    import { createRequest, writeResponse } from 'astro/app/node';
    import { createServer } from 'node:http';
    
    const app = createApp();
    
    const server = createServer(async (req, res) => {
      const request = createRequest(req);
      const response = await app.render(request);
      await writeResponse(response, res);
    });
  • #15755 f9ee868 Thanks @matthewp! - Adds a new security.serverIslandBodySizeLimit configuration option

    Server island POST endpoints now enforce a body size limit, similar to the existing security.actionBodySizeLimit for Actions. The new option defaults to 1048576 (1 MB) and can be configured independently.

    Requests exceeding the limit are rejected with a 413 response. You can customize the limit in your Astro config:

    export default defineConfig({
      security: {
        serverIslandBodySizeLimit: 2097152, // 2 MB
      },
    });
  • #15529 a509941 Thanks @florian-lefebvre! - Adds a new build-in font provider npm to access fonts installed as NPM packages

    You can now add web fonts specified in your package.json through Astro's type-safe Fonts API. The npm font provider allows you to add fonts either from locally installed packages in node_modules or from a CDN.

    Set fontProviders.npm() as your fonts provider along with the required name and cssVariable values, and add options as needed:

    import { defineConfig, fontProviders } from 'astro/config';
    
    export default defineConfig({
      experimental: {
        fonts: [
          {
            name: 'Roboto',
            provider: fontProviders.npm(),
            cssVariable: '--font-roboto',
          },
        ],
      },
    });

    See the NPM font provider reference documentation for more details.

  • #15471 32b4302 Thanks @ematipico! - Adds a new experimental flag queuedRendering to enable a queue-based rendering engine

    The new engine is based on a two-pass process, where the first pass
    traverses the tree of components, emits an ordered queue, and then the queue is rendered.

    The new engine does not use recursion, and comes with two customizable options.

    Early benchmarks showed significant speed improvements and memory efficiency in big projects.

    Queue-rendered based

    The new engine can be enabled in your Astro config with experimental.queuedRendering.enabled set to true, and can be further customized with additional sub-features.

    // astro.config.mjs
    export default defineConfig({
      experimental: {
        queuedRendering: {
          enabled: true,
        },
      },
    });

    Pooling

    With the new engine enabled, you now have the option to have a pool of nodes that can be saved and reused across page rendering. Node pooling has no effect when rendering pages on demand (SSR) because these rendering requests don't share memory. However, it can be very useful for performance when building static pages.

    // astro.config.mjs
    export default defineConfig({
      experimental: {
        queuedRendering: {
          enabled: true,
          poolSize: 2000, // store up to 2k nodes to be reused across renderers
        },
      },
    });

    Content caching

    The new engine additionally unlocks a new contentCache option. This allows you to cache values of nodes during the rendering phase. This is currently a boolean feature with no further customization (e.g. size of cache) that uses sensible defaults for most large content collections:

    When disabled, the pool engine won't cache strings, but only types.

    // astro.config.mjs
    export default defineConfig({
      experimental: {
        queuedRendering: {
          enabled: true,
          contentCache: true, // enable re-use of node values
        },
      },
    });

    For more information on enabling and using this feature in your project, see the experimental queued rendering docs for more details.

  • #14888 4cd3fe4 Thanks @OliverSpeir! - Updates astro add cloudflare to better setup types, by adding ./worker-configuration.d.ts to tsconfig includes and a generate-types script to package.json

  • #15646 0dd9d00 Thanks @delucis! - Removes redundant fetchpriority attributes from the output of Astro’s <Image> component

    Previously, Astro would always include fetchpriority="auto" on images not using the priority attribute.
    However, this is the default value, so specifying it is redundant. This change omits the attribute by default.

  • #15291 89b6cdd Thanks @florian-lefebvre! - Removes the experimental.fonts flag and replaces it with a new configuration option fonts - (v6 upgrade guidance)

  • #15495 5b99e90 Thanks @leekeh! - Adds a new middlewareMode adapter feature to replace the previous edgeMiddleware option.

    This feature only impacts adapter authors. If your adapter supports edgeMiddleware, you should upgrade to the new middlewareMode option to specify the middleware mode for your adapter as soon as possible. The edgeMiddleware feature is deprecated and will be removed in a future major release.

    export default function createIntegration() {
      return {
        name: '@example/my-adapter',
        hooks: {
          'astro:config:done': ({ setAdapter }) => {
            setAdapter({
              name: '@example/my-adapter',
              serverEntrypoint: '@example/my-adapter/server.js',
              adapterFeatures: {
    -            edgeMiddleware: true
    +            middlewareMode: 'edge'
              }
            });
          },
        },
      };
    }
  • #15694 66449c9 Thanks @matthewp! - Adds preserveBuildClientDir option to adapter features

    Adapters can now opt in to preserving the client/server directory structure for static builds by setting preserveBuildClientDir: true in their adapter features. When enabled, static builds will output files to build.client instead of directly to outDir.

    This is useful for adapters that require a consistent directory structure regardless of the build output type, such as deploying to platforms with specific file organization requirements.

    // my-adapter/index.js
    export default function myAdapter() {
      return {
        name: 'my-adapter',
        hooks: {
          'astro:config:done': ({ setAdapter }) => {
            setAdapter({
              name: 'my-adapter',
              adapterFeatures: {
                buildOutput: 'static',
                preserveBuildClientDir: true,
              },
            });
          },
        },
      };
    }
  • #15332 7c55f80 Thanks @matthewp! - Adds a fileURL option to renderMarkdown in content loaders, enabling resolution of relative image paths. When provided, relative image paths in markdown will be resolved relative to the specified file URL and included in metadata.localImagePaths.

    const loader = {
      name: 'my-loader',
      load: async ({ store, renderMarkdown }) => {
        const content = `
    # My Post
    
    ![Local image](./image.png)
    `;
        // Provide a fileURL to resolve relative image paths
        const fileURL = new URL('./posts/my-post.md', import.meta.url);
        const rendered = await renderMarkdown(content, { fileURL });
        // rendered.metadata.localImagePaths now contains the resolved image path
      },
    };
  • #15407 aedbbd8 Thanks @ematipico! - Adds support for responsive images when security.csp is enabled, out of the box.

    Astro's implementation of responsive image styles has been updated to be compatible with a configured Content Security Policy.

    Instead of, injecting style elements at runtime, Astro will now generate your styles at build time using a combination of class="" and data-* attributes. This means that your processed styles are loaded and hashed out of the box by Astro.

    If you were previously choosing between Astro's CSP feature and including responsive images on your site, you may now use them together.

  • #15543 d43841d Thanks @Princesseuh! - Adds a new experimental.rustCompiler flag to opt into the experimental Rust-based Astro compiler

    This experimental compiler is faster, provides better error messages, and generally has better support for modern JavaScript, TypeScript, and CSS features.

    After enabling in your Astro config, the @astrojs/compiler-rs package must also be installed into your project separately:

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

    This new compiler is still in early development and may exhibit some differences compared to the existing Go-based compiler. Notably, this compiler is generally more strict in regard to invalid HTML syntax and may throw errors in cases where the Go-based compiler would have been more lenient. For example, unclosed tags (e.g. <p>My paragraph) will now result in errors.

    For more information about using this experimental feature in your project, especially regarding expected differences and limitations, please see the experimental Rust compiler reference docs. To give feedback on the compiler, or to keep up with its development, see the RFC for a new compiler for Astro for more information and discussion.

  • #15349 a257c4c Thanks @ascorbic! - Passes collection name to live content loaders

    Live content collection loaders now receive the collection name as part of their parameters. This is helpful for loaders that manage multiple collections or need to differentiate behavior based on the collection being accessed.

    export function storeLoader({ field, key }) {
      return {
        name: 'store-loader',
        loadCollection: async ({ filter, collection }) => {
          // ...
        },
        loadEntry: async ({ filter, collection }) => {
          // ...
        },
      };
    }
  • #15006 f361730 Thanks @florian-lefebvre! - Adds new session driver object shape

    For greater flexibility and improved consistency with other Astro code, session drivers are now specified as an object:

    -import { defineConfig } from 'astro/config'
    +import { defineConfig, sessionDrivers } from 'astro/config'
    
    export default defineConfig({
      session: {
    -    driver: 'redis',
    -    options: {
    -      url: process.env.REDIS_URL
    -    },
    +    driver: sessionDrivers.redis({
    +      url: process.env.REDIS_URL
    +    }),
      }
    })

    Specifying the session driver as a string has been deprecated, but will continue to work until this feature is removed completely in a future major version. The object shape is the current recommended and documented way to configure a session driver.

  • #15291 89b6cdd Thanks @florian-lefebvre! - Adds a new Fonts API to provide first-party support for adding custom fonts in Astro.

    This 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 preloading and fallback font generation.

    To enable this feature, configure fonts with one or more fonts:

    import { defineConfig, fontProviders } from 'astro/config';
    
    export default defineConfig({
      fonts: [
        {
          provider: fontProviders.fontsource(),
          name: 'Roboto',
          cssVariable: '--font-roboto',
        },
      ],
    });

    Import and include the <Font /> component with the required cssVariable property in the head of your page, usually in a dedicated Head.astro component or in a layout component directly:

    ---
    // src/layouts/Layout.astro
    import { Font } from 'astro:assets';
    ---
    
    <html>
      <head>
        <Font cssVariable="--font-roboto" preload />
      </head>
      <body>
        <slot />
      </body>
    </html>

    In any page rendered with that layout, including the layout component itself, you can now define styles with your font's cssVariable to apply your custom font.

    In the following example, the <h1> heading will have the custom font applied, while the paragraph <p> will not.

    ---
    // src/pages/example.astro
    import Layout from '../layouts/Layout.astro';
    ---
    
    <Layout>
      <h1>In a galaxy far, far away...</h1>
    
      <p>Custom fonts make my headings much cooler!</p>
    
      <style>
        h1 {
          font-family: var('--font-roboto');
        }
      </style>
    </Layout>

    Visit the updated fonts guide to learn more about adding custom fonts to your project.

  • #14550 9c282b5 Thanks @ascorbic! - Adds 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.

    Live collections vs build-time collections

    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 was no method for updating the data store between builds, meaning any updates to the data needed a full site deploy, even if the pages are rendered on demand. This meant that content collections were not suitable for pages that update frequently. Instead, these pages tended to access the APIs directly in the frontmatter. This worked, but it led to a lot of boilerplate, and meant users didn't benefit from the simple, unified API that content loaders offer. In most cases, users tended to individually create loader libraries shared between pages.

    Live content collections (introduced experimentally in Astro 5.10) 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.

    How to use

    To use live collections, 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 content loader using the new defineLiveCollection() function from the astro:content module:

    import { defineLiveCollection } from 'astro:content';
    import { storeLoader } from '@mystore/astro-loader';
    
    const products = defineLiveCollection({
      loader: storeLoader({
        apiKey: process.env.STORE_API_KEY,
        endpoint: 'https://api.mystore.com/v1',
      }),
    });
    
    export const collections = { products };

    You can then use the getLiveCollection() and getLiveEntry() functions to access your live data, along with error handling (since anything can happen when requesting live data!):

    ---
    import { getLiveCollection, getLiveEntry, render } from 'astro:content';
    // Get all products
    const { entries: allProducts, error } = await getLiveCollection('products');
    if (error) {
      // Handle error appropriately
      console.error(error.message);
    }
    
    // Get products with a filter (if supported by your loader)
    const { entries: electronics } = await getLiveCollection('products', { category: 'electronics' });
    
    // Get a single product by ID (string syntax)
    const { entry: product, error: productError } = await getLiveEntry('products', Astro.params.id);
    if (productError) {
      return Astro.redirect('/404');
    }
    
    // Get a single product with a custom query (if supported by your loader) using a filter object
    const { entry: productBySlug } = await getLiveEntry('products', { slug: Astro.params.slug });
    const { Content } = await render(product);
    ---
    
    <h1>{product.data.title}</h1>
    <Content />

    Upgrading from experimental live collections

    If you were using the experimental feature, you must remove the experimental.liveContentCollections flag from your astro.config.* file:

     export default defineConfig({
       // ...
    -  experimental: {
    -    liveContentCollections: true,
    -  },
     });

    No other changes to your project code are required as long as you have been keeping up with Astro 5.x patch releases, which contained breaking changes to this experimental feature. If you experience problems with your live collections after upgrading to Astro v6 and removing this flag, please review the Astro CHANGELOG from 5.10.2 onwards for any potential updates you might have missed, or follow the current v6 documentation for live collections.

  • #15548 5b8f573 Thanks @florian-lefebvre! - Adds a new optional embeddedLangs prop to the <Code /> component to support languages beyond the primary lang

    This allows, for example, highlighting .vue files with a <script setup lang="tsx"> block correctly:

    ---
    import { Code } from 'astro:components';
    
    const code = `
    <script setup lang="tsx">
    const Text = ({ text }: { text: string }) => <div>{text}</div>;
    </script>
    
    <template>
      <Text text="hello world" />
    </template>`;
    ---
    
    <Code {code} lang="vue" embeddedLangs={['tsx']} />

    See the <Code /> component documentation for more details.

  • #14826 170f64e Thanks @florian-lefebvre! - Adds an option prerenderConflictBehavior to configure the behavior of conflicting prerendered routes

    By default, Astro warns you during the build about any conflicts between multiple dynamic routes that can result in the same output path. For example /blog/[slug] and /blog/[...all] both could try to prerender the /blog/post-1 path. In such cases, Astro renders only the highest priority route for the conflicting path. This allows your site to build successfully, although you may discover that some pages are rendered by unexpected routes.

    With the new prerenderConflictBehavior configuration option, you can now configure this further:

    • prerenderConflictBehavior: 'error' fails the build
    • prerenderConflictBehavior: 'warn' (default) logs a warning and the highest-priority route wins
    • prerenderConflictBehavior: 'ignore' silently picks the highest-priority route when conflicts occur
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
    +    prerenderConflictBehavior: 'error',
    });
  • #14946 95c40f7 Thanks @ematipico! - Removes the experimental.csp flag and replaces it with a new configuration option security.csp - (v6 upgrade guidance)

  • #15579 08437d5 Thanks @ascorbic! - Adds two new experimental flags for a Route Caching API and further configuration-level Route Rules for controlling SSR response caching.

    Route caching gives you a platform-agnostic way to cache server-rendered responses, based on web standard cache headers. You set caching directives in your routes using 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 adapter. You can also define cache rules for routes declaratively in your config using experimental.routeRules, without modifying route code.

    This feature requires on-demand rendering. Prerendered pages are already static and do not use route caching.

    Getting started

    Enable the feature by configuring experimental.cache with a cache provider in your Astro config:

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    import node from '@astrojs/node';
    import { memoryCache } from 'astro/config';
    
    export default defineConfig({
      adapter: node({ mode: 'standalone' }),
      experimental: {
        cache: {
          provider: memoryCache(),
        },
      },
    });

    Using Astro.cache and context.cache

    In .astro pages, use Astro.cache.set() to control caching:

    ---
    // src/pages/index.astro
    Astro.cache.set({
      maxAge: 120, // Cache for 2 minutes
      swr: 60, // Serve stale for 1 minute while revalidating
      tags: ['home'], // Tag for targeted invalidation
    });
    ---
    
    <html><body>Cached page</body></html>

    In API routes and middleware, use context.cache:

    // src/pages/api/data.ts
    export function GET(context) {
      context.cache.set({
        maxAge: 300,
        tags: ['api', 'data'],
      });
      return Response.json({ ok: true });
    }

    Cache options

    cache.set() accepts the following options:

    • maxAge (number): Time in seconds the response is considered fresh.
    • swr (number): Stale-while-revalidate window in seconds. During this window, stale content is served while a fresh response is generated in the background.
    • tags (string[]): Cache tags for targeted invalidation. Tags accumulate across multiple set() calls within a request.
    • lastModified (Date): When multiple set() calls provide lastModified, the most recent date wins.
    • etag (string): Entity tag for conditional requests.

    Call cache.set(false) to explicitly opt out of caching for a request.

    Multiple calls to cache.set() within a single request are merged: scalar values use last-write-wins, lastModified uses most-recent-wins, and tags accumulate.

    Invalidation

    Purge cached entries by tag or path using cache.invalidate():

    // Invalidate all entries tagged 'data'
    await context.cache.invalidate({ tags: ['data'] });
    
    // Invalidate a specific path
    await context.cache.invalidate({ path: '/api/data' });

    Config-level route rules

    Use experimental.routeRules to set default cache options for routes without modifying route code. Supports Nitro-style shortcuts for ergonomic configuration:

    import { memoryCache } from 'astro/config';
    
    export default defineConfig({
      experimental: {
        cache: {
          provider: memoryCache(),
        },
        routeRules: {
          // Shortcut form (Nitro-style)
          '/api/*': { swr: 600 },
    
          // Full form with nested cache
          '/products/*': { cache: { maxAge: 3600, tags: ['products'] } },
        },
      },
    });

    Route patterns support static paths, dynamic parameters ([slug]), and rest parameters ([...path]). Per-route cache.set() calls merge with (and can override) the config-level defaults.

    You can also read the current cache state via cache.options:

    const { maxAge, swr, tags } = context.cache.options;

    Cache providers

    Cache behavior is determined by the configured cache provider. There are two types:

    • CDN providers set response headers (e.g. CDN-Cache-Control, Cache-Tag) and let the CDN handle caching. Astro strips these headers before sending the response to the client.
    • Runtime providers implement onRequest() to intercept and cache responses in-process, adding an X-Astro-Cache header (HIT/MISS/STALE) for observability.

    Built-in memory cache provider

    Astro includes a built-in, in-memory LRU runtime cache provider. Import memoryCache from astro/config to configure it.

    Features:

    • In-memory LRU cache with configurable max entries (default: 1000)
    • Stale-while-revalidate support
    • Tag-based and path-based invalidation
    • X-Astro-Cache response header: HIT, MISS, or STALE
    • Query parameter sorting for better hit rates (?b=2&a=1 and ?a=1&b=2 hit the same entry)
    • Common tracking parameters (utm_*, fbclid, gclid, etc.) excluded from cache keys by default
    • Vary header support — responses that set Vary automatically get separate cache entries per variant
    • Configurable query parameter filtering via query.exclude (glob patterns) and query.include (allowlist)

    For more information on enabling and using this feature in your project, see the Experimental Route Caching docs.
    For a complete overview and to give feedback on this experimental API, see the Route Caching RFC.

  • #15483 7be3308 Thanks @florian-lefebvre! - Adds streaming option to the createApp() function in the Adapter API, mirroring the same functionality available when creating a new App instance

    An adapter's createApp() function now accepts streaming (defaults to true) as an option. HTML streaming breaks a document into chunks to send over the network and render on the page in order. This normally results in visitors seeing your HTML as fast as possible but factors such as network conditions and waiting for data fetches can block page rendering.

    HTML streaming helps with performance and generally provides a better visitor experience. In most cases, disabling streaming is not recommended.

    However, when you need to disable HTML streaming (e.g. your host only supports non-streamed HTML caching at the CDN level), you can opt out of the default behavior by passing streaming: false to createApp():

    import { createApp } from 'astro/app/entrypoint';
    
    const app = createApp({ streaming: false });

    See more about the createApp() function in the Adapter API reference.

Patch Changes

  • #15423 c5ea720 Thanks @matthewp! - Improves error message when a dynamic redirect destination does not match any existing route.

    Previously, configuring a redirect like /categories/[category]/categories/[category]/1 in static output mode would fail with a misleading "getStaticPaths required" error. Now, Astro detects this early and provides a clear error explaining that the destination does not match any existing route.

  • #15167 4fca170 Thanks @HiDeoo! - Fixes an issue where CSS from unused components, when using content collections, could be incorrectly included between page navigations in development mode.

  • #15565 30cd6db Thanks @ematipico! - Fixes an issue where the use of the Astro internal logger couldn't work with Cloudflare Vite plugin.

  • #15508 2c6484a Thanks @KTibow! - Fixes behavior when shortcuts are used before server is ready

  • #15125 6feb0d7 Thanks @florian-lefebvre! - Improves JSDoc annotations for AstroGlobal, AstroSharedContext and APIContext types

  • #15712 7ac43c7 Thanks @florian-lefebvre! - Improves astro info by supporting more operating systems when copying the information to the clipboard.

  • #15054 22db567 Thanks @matthewp! - Improves zod union type error messages to show expected vs received types instead of generic "Invalid input"

  • #15064 caf5621 Thanks @ascorbic! - Fixes a bug that caused incorrect warnings of duplicate entries to be logged by the glob loader when editing a file

  • #15801 01db4f3 Thanks @ascorbic! - Improves the experience of working with experimental route caching in dev mode by replacing some errors with silent no-ops, avoiding the need to write conditional logic to handle different modes

    Adds a cache.enabled property to CacheLike so libraries can check whether caching is active without try/catch.

  • #15562 e14a51d Thanks @florian-lefebvre! - Removes types for the astro:ssr-manifest module, which was removed

  • #15542 9760404 Thanks @rururux! - Improves rendering by preserving hidden="until-found" value in attributes

  • #15044 7cac71b Thanks @florian-lefebvre! - Removes an exposed internal API of the preview server

  • #15573 d789452 Thanks @matthewp! - Clear the route cache on content changes so slug pages reflect updated data during dev.

  • #15308 89cbcfa Thanks @matthewp! - Fixes styles missing in dev for prerendered pages when using Cloudflare adapter

  • #15435 957b9fe Thanks @rururux! - Improves compatibility of the built-in image endpoint with runtimes that don't support CJS dependencies correctly

  • #15640 4c1a801 Thanks @ematipico! - Reverts the support of Shiki with CSP. Unfortunately, after exhaustive tests, the highlighter can't be supported to cover all cases.

    Adds a warning when both Content Security Policy (CSP) and Shiki syntax highlighting are enabled, as they are incompatible due to Shiki's use of inline styles

  • #15415 cc3c46c Thanks @ematipico! - Fixes an issue where CSP headers were incorrectly injected in the development server.

  • #15412 c546563 Thanks @florian-lefebvre! - Improves the AstroAdapter type and how legacy adapters are handled

  • #15322 18e0980 Thanks @matthewp! - Prevents missing CSS when using both SSR and prerendered routes

  • #15760 f49a27f Thanks @ematipico! - Fixed an issue where queued rendering wasn't correctly re-using the saved nodes.

  • #15277 cb99214 Thanks @ematipico! - Fixes an issue where the function createShikiHighlighter would always create a new Shiki highlighter instance. Now the function returns a cached version of the highlighter based on the Shiki options. This should improve the performance for sites that heavily rely on Shiki and code in their pages.

  • #15394 5520f89 Thanks @florian-lefebvre! - Fixes a case where using the Fonts API with netlify dev wouldn't work because of query parameters

  • #15605 f6473fd Thanks @ascorbic! - Improves .astro component SSR rendering performance by up to 2x.

    This includes several optimizations to the way that Astro generates and renders components on the server. These are mostly micro-optimizations, but they add up to a significant improvement in performance. Most pages will benefit, but pages with many components will see the biggest improvement, as will pages with lots of strings (e.g. text-heavy pages with lots of HTML elements).

  • #15721 e6e146c Thanks @matthewp! - Fixes action route handling to return 404 for requests to prototype method names like constructor or toString used as action paths

  • #15497 a93c81d Thanks @matthewp! - Fix dev reloads for content collection Markdown updates under Vite 7.

  • #15780 e0ac125 Thanks @ematipico! - Prevents vite.envPrefix misconfiguration from exposing access: "secret" environment variables in client-side bundles. Astro now throws a clear error at startup if any vite.envPrefix entry matches a variable declared with access: "secret" in env.schema.

    For example, the following configuration will throw an error for API_SECRET because it's defined as secret its name matches ['PUBLIC_', 'API_'] defined in env.schema:

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      env: {
        schema: {
          API_SECRET: envField.string({ context: 'server', access: 'secret', optional: true }),
          API_URL: envField.string({ context: 'server', access: 'public', optional: true }),
        },
      },
      vite: {
        envPrefix: ['PUBLIC_', 'API_'],
      },
    });
  • #15514 999a7dd Thanks @veeceey! - Fixes font flash (FOUT) during ClientRouter navigation by preserving inline <style> elements and font preload links in the head during page transitions.

    Previously, @font-face declarations from the <Font> component were removed and re-inserted on every client-side navigation, causing the browser to re-evaluate them.

  • #15560 170ed89 Thanks @z0mt3c! - Fix X-Forwarded-Proto validation when allowedDomains includes both protocol and hostname fields. The protocol check no longer fails due to hostname mismatch against the hardcoded test URL.

  • #15704 862d77b Thanks @umutkeltek! - Fixes i18n fallback middleware intercepting non-404 responses

    The fallback middleware was triggering for all responses with status >= 300, including legitimate 3xx redirects, 403 forbidden, and 5xx server errors. This broke auth flows and form submissions on localized server routes. The fallback now correctly only triggers for 404 (page not found) responses.

  • #15661 7150a2e Thanks @ematipico! - Fixes a build error when generating projects with 100k+ static routes.

  • #15580 a92333c Thanks @ematipico! - Fixes a build error when generating projects with a large number of static routes

  • #15176 9265546 Thanks @matthewp! - Fixes hydration for framework components inside MDX when using Astro.slots.render()

    Previously, when multiple framework components with client:* directives were passed as named slots to an Astro component in MDX, only the first slot would hydrate correctly. Subsequent slots would render their HTML but fail to include the necessary hydration scripts.

  • #15506 074901f Thanks @ascorbic! - Fixes a race condition where concurrent requests to dynamic routes in the dev server could produce incorrect params.

  • #15444 10b0422 Thanks @AhmadYasser1! - Fixes Astro.rewrite returning 404 when rewriting to a URL with non-ASCII characters

    When rewriting to a path containing non-ASCII characters (e.g., /redirected/héllo), the route lookup compared encoded distURL hrefs against decoded pathnames, causing the comparison to always fail and resulting in a 404. This fix compares against the encoded pathname instead.

  • #15728 12ca621 Thanks @SvetimFM! - Improves internal state retention for persisted elements during view transitions, especially avoiding WebGL context loss in Safari and resets of CSS transitions and iframes in modern Chromium and Firefox browsers

  • #15279 8983f17 Thanks @ematipico! - Fixes an issue where the dev server would serve files like /README.md from the project root when they shouldn't be accessible. A new route guard middleware now blocks direct URL access to files that exist outside of srcDir and publicDir, returning a 404 instead.

  • #15703 829182b Thanks @matthewp! - Fixes server islands returning a 500 error in dev mode for adapters that do not set adapterFeatures.buildOutput (e.g. @astrojs/netlify)

  • #15749 573d188 Thanks @ascorbic! - Fixes a bug that caused session.regenerate() to silently lose session data

    Previously, regenerated session data was not saved under the new session ID unless set() was also called.

  • #15549 be1c87e Thanks @0xRozier! - Fixes an issue where original (unoptimized) images from prerendered pages could be kept in the build output during SSR builds.

  • #15454 b47a4e1 Thanks @Fryuni! - Fixes a race condition in the content layer which could result in dropped content collection entries.

  • #15685 1a323e5 Thanks @jcayzac! - Fix regression where SVG images in content collection image() fields could not be rendered as inline components. This behavior is now restored while preserving the TLA deadlock fix.

  • #15603 5bc2b2c Thanks @0xRozier! - Fixes a deadlock that occurred when using SVG images in content collections

  • #15385 9e16d63 Thanks @matthewp! - Fixes content layer loaders that use dynamic imports

    Content collection loaders can now use await import() and import.meta.glob() to dynamically import modules during build. Previously, these would fail with "Vite module runner has been closed."

  • #15565 30cd6db Thanks @ematipico! - Fixes an issue where the use of the Code component would result in an unexpected error.

  • #15125 6feb0d7 Thanks @florian-lefebvre! - Fixes remote images Etag header handling by disabling internal cache

  • #15317 7e1e35a Thanks @matthewp! - Fixes ?raw imports failing when used in both SSR and prerendered routes

  • #15809 94b4a46 Thanks @Princesseuh! - Fixes fit defaults not being applied unless layout was also specified

  • #15563 e959698 Thanks @ematipico! - Fixes an issue where warnings would be logged during the build using one of the official adapters

  • #15121 06261e0 Thanks @ematipico! - Fixes a bug where the Astro, with the Cloudflare integration, couldn't correctly serve certain routes in the development server.

  • #15585 98ea30c Thanks @matthewp! - Add a default body size limit for server actions to prevent oversized requests from exhausting memory.

  • #15264 11efb05 Thanks @florian-lefebvre! - Lower the Node version requirement to allow running on Stackblitz until it supports v22

  • #15778 4ebc1e3 Thanks @ematipico! - Fixes an issue where the computed clientAddress was incorrect in cases of a Request header with multiple values. The clientAddress is now also validated to contain only characters valid in IP addresses, rejecting injection payloads.

  • #15565 30cd6db Thanks @ematipico! - Fixes an issue where the new Astro v6 development server didn't log anything when navigating the pages.

  • #15024 22c48ba Thanks @florian-lefebvre! - Fixes a case where JSON schema generation would fail for unrepresentable types

  • #15669 d5a888b Thanks @florian-lefebvre! - Removes the cssesc dependency

    This CommonJS dependency could sometimes cause errors because Astro is ESM-only. It is now replaced with a built-in ESM-friendly implementation.

  • #15740 c5016fc Thanks @matthewp! - Removes an escape hatch that skipped attribute escaping for URL values containing &, ensuring all dynamic attribute values are consistently escaped

  • #15756 b6c64d1 Thanks @matthewp! - Hardens the dev server by validating Sec-Fetch metadata headers to restrict cross-origin subresource requests

  • #15744 fabb710 Thanks @matthewp! - Fixes cookie handling during error page rendering to ensure cookies set by middleware are consistently included in the response

  • #15776 e9a9cc6 Thanks @matthewp! - Hardens error page response merging to ensure framing headers from the original response are not carried over to the rendered error page

  • #15759 39ff2a5 Thanks @matthewp! - Adds a new bodySizeLimit option to the @astrojs/node adapter

    You can now configure a maximum allowed request body size for your Node.js standalone server. The default limit is 1 GB. Set the value in bytes, or pass 0 to disable the limit entirely:

    import node from '@astrojs/node';
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      adapter: node({
        mode: 'standalone',
        bodySizeLimit: 1024 * 1024 * 100, // 100 MB
      }),
    });
  • #15777 02e24d9 Thanks @matthewp! - Fixes CSRF origin check mismatch by passing the actual server listening port to createRequest, ensuring the constructed URL origin includes the correct port (e.g., http://localhost:4321 instead of http://localhost). Also restricts X-Forwarded-Proto to only be trusted when allowedDomains is configured.

  • #15742 9d9699c Thanks @matthewp! - Hardens clientAddress resolution to respect security.allowedDomains for X-Forwarded-For, consistent with the existing handling of X-Forwarded-Host, X-Forwarded-Proto, and X-Forwarded-Port. The X-Forwarded-For header is now only used to determine Astro.clientAddress when the request's host has been validated against an allowedDomains entry. Without a matching domain, clientAddress falls back to the socket's remote address.

  • #15768 6328f1a Thanks @matthewp! - Hardens internal cookie parsing to use a null-prototype object consistently for the fallback path, aligning with how the cookie library handles parsed values

  • #15125 6feb0d7 Thanks @florian-lefebvre! - Fixes images not working in development when using setups with port forwarding

  • #15811 2ba0db5 Thanks @ematipico! - Fixes integration-injected scripts (e.g. Alpine.js via injectScript()) not being loaded in the dev server when using non-runnable environment adapters like @astrojs/cloudflare.

  • #15208 8dbdd8e Thanks @matthewp! - Makes session.driver optional in config schema, allowing adapters to provide default drivers

    Adapters like Cloudflare, Netlify, and Node provide default session drivers, so users can now configure session options (like ttl) without explicitly specifying a driver.

  • #15260 abca1eb Thanks @ematipico! - Fixes an issue where adding new pages weren't correctly shown when using the development server.

  • #15591 1ed07bf Thanks @renovate! - Upgrades devalue to v5.6.3

  • #15137 2f70bf1 Thanks @matthewp! - Adds legacy.collectionsBackwardsCompat flag that restores v5 backwards compatibility behavior for legacy content collections - (v6 upgrade guidance)

    When enabled, this flag allows:

    • Collections defined without loaders (automatically get glob loader)
    • Collections with type: 'content' or type: 'data'
    • Config files located at src/content/config.ts (legacy location)
    • Legacy entry API: entry.slug and entry.render() methods
    • Path-based entry IDs instead of slug-based IDs
    // astro.config.mjs
    export default defineConfig({
      legacy: {
        collectionsBackwardsCompat: true,
      },
    });

    This is a temporary migration helper for v6 upgrades. Migrate collections to the Content Layer API, then disable this flag.

  • #15550 58df907 Thanks @florian-lefebvre! - Improves the JSDoc annotations for the AstroAdapter type

  • #15696 a9fd221 Thanks @Princesseuh! - Fixes images not working in MDX when using the Cloudflare adapter in certain cases

  • #15386 a0234a3 Thanks @OliverSpeir! - Updates astro add cloudflare to use the latest valid compatibility_date in the wrangler config, if available

  • #15036 f125a73 Thanks @florian-lefebvre! - Fixes certain aliases not working when using images in JSON files with the content layer

  • #15693 4db2089 Thanks @ArmandPhilippot! - Fixes the links to Astro Docs to match the v6 structure.

  • #15093 8d5f783 Thanks @matthewp! - Reduces build memory by filtering routes per environment so each only builds the pages it needs

  • #15268 54e5cc4 Thanks @rururux! - fix: avoid creating unused images during build in Picture component

  • #15757 631aaed Thanks @matthewp! - Hardens URL pathname normalization to consistently handle backslash characters after decoding, ensuring middleware and router see the same canonical pathname

  • #15337 7ff7b11 Thanks @ematipico! - Fixes a bug where the development server couldn't serve newly created new pages while the development server is running.

  • #15535 dfe2e22 Thanks @florian-lefebvre! - Fixes the types of createApp() exported from astro/app/entrypoint

  • #15073 2a39c32 Thanks @ascorbic! - Don't log an error when there is no content config

  • #15717 4000aaa Thanks @matthewp! - Ensures that URLs with multiple leading slashes (e.g. //admin) are normalized to a single slash before reaching middleware, so that pathname checks like context.url.pathname.startsWith('/admin') work consistently regardless of the request URL format

  • #15450 50c9129 Thanks @florian-lefebvre! - Fixes a case where build.serverEntry would not be respected when using the new Adapter API

  • #15331 4592be5 Thanks @matthewp! - Fixes an issue where API routes would overwrite public files during build. Public files now correctly take priority over generated routes in both dev and build modes.

  • #15414 faedcc4 Thanks @sapphi-red! - Fixes a bug where some requests to the dev server didn't start with the leading /.

  • #15419 a18d727 Thanks @ematipico! - Fixes an issue where the add command could accept any arbitrary value, leading the possible command injections. Now add and --add accepts
    values that are only acceptable npmjs.org names.

  • #15507 07f6610 Thanks @matthewp! - Avoid bundling SSR renderers when only API endpoints are dynamic

  • #15125 6feb0d7 Thanks @florian-lefebvre! - Reduces Astro’s install size by around 8 MB

  • #15752 918d394 Thanks @ascorbic! - Fixes an issue where a session ID from a cookie with no matching server-side data was accepted as-is. The session now generates a new ID when the cookie value has no corresponding storage entry.

  • #15743 3b4252a Thanks @matthewp! - Hardens config-based redirects with catch-all parameters to prevent producing protocol-relative URLs (e.g. //example.com) in the Location header

  • #15761 8939751 Thanks @ematipico! - Fixes an issue where it wasn't possible to set experimental.queuedRendering.poolSize to 0.

  • #15633 9d293c2 Thanks @jwoyo! - Fixes a case where <script> tags from components passed as slots to server islands were not included in the response

  • #15491 6c60b05 Thanks @matthewp! - Fixes a case where setting vite.server.allowedHosts: true was turned into an invalid array

  • #15459 a4406b4 Thanks @florian-lefebvre! - Fixes a case where context.csp was logging warnings in development that should be logged in production only

  • #15125 6feb0d7 Thanks @florian-lefebvre! - Enables the ClientRouter to preserve the original hash part of the target URL during server side redirects.

  • #15133 53b125b Thanks @HiDeoo! - Fixes an issue where adding or removing <style> tags in Astro components would not visually update styles during development without restarting the development server.

  • #15362 dbf71c0 Thanks @jcayzac! - Fixes inferSize being kept in the HTML attributes of the emitted <img> when that option is used with an image that is not remote.

  • #15421 bf62b6f Thanks @Princesseuh! - Removes unintended logging

  • #15732 2ce9e74 Thanks @florian-lefebvre! - Updates docs links to point to the stable release

  • #15718 14f37b8 Thanks @florian-lefebvre! - Fixes a case where internal headers may leak when rendering error pages

  • #15214 6bab8c9 Thanks @ematipico! - Fixes an issue where the internal performance timers weren't correctly updated to reflect new build pipeline.

  • #15112 5751d2b Thanks @HiDeoo! - Fixes a Windows-specific build issue when importing an Astro component with a <script> tag using an import alias.

  • #15345 840fbf9 Thanks @matthewp! - Fixes an issue where .sql files (and other non-asset module types) were incorrectly moved to the client assets folder during SSR builds, causing "no such module" errors at runtime.

    The ssrMoveAssets function now reads the Vite manifest to determine which files are actual client assets (CSS and static assets like images) and only moves those, leaving server-side module files in place.

  • #15259 8670a69 Thanks @ematipico! - Fixes an issue where styles weren't correctly reloaded when using the @astrojs/cloudflare adapter.

  • #15473 d653b86 Thanks @matthewp! - Improves Host header handling for SSR deployments behind proxies

  • #15047 5580372 Thanks @matthewp! - Fixes wrangler config template in astro add cloudflare to use correct entrypoint and compatibility date

  • #14589 7038f07 Thanks @43081j! - Improves CLI styling

  • #15586 35bc814 Thanks @matthewp! - Fixes an issue where allowlists were not being enforced when handling remote images

  • #15422 68770ef Thanks @matthewp! - Upgrade to @astrojs/compiler@3.0.0-beta

  • #15205 12adc55 Thanks @martrapp! - Fixes an issue where the astro:page-load event did not fire on initial page loads.

  • #15125 6feb0d7 Thanks @florian-lefebvre! - BREAKING CHANGE to the experimental Fonts API only

    Changes the font format downloaded by default when using the experimental Fonts API. Additionally, adds a new formats configuration option to specify which font formats to download.

    Previously, Astro was opinionated about which font sources would be kept for usage, mainly keeping woff2 and woff files.

    You can now specify what font formats should be downloaded (if available). Only woff2 files are downloaded by default.

    What should I do?

    If you were previously relying on Astro downloading the woff format, you will now need to specify this explicitly with the new formats configuration option. Additionally, you may also specify any additional file formats to download if available:

    // astro.config.mjs
    import { defineConfig, fontProviders } from 'astro/config'
    
    export default defineConfig({
        experimental: {
            fonts: [{
                name: 'Roboto',
                cssVariable: '--font-roboto',
                provider: fontProviders.google(),
    +            formats: ['woff2', 'woff', 'otf']
            }]
        }
    })
  • #15179 8c8aee6 Thanks @HiDeoo! - Fixes an issue when importing using an import alias a file with a name matching a directory name.

  • #15036 f125a73 Thanks @florian-lefebvre! - Fixes a vite warning log during builds when using npm

  • #15269 6f82aae Thanks @ematipico! - Fixes a regression where build.serverEntry stopped working as expected.

  • #15053 674b63f Thanks @matthewp! - Excludes astro:* and virtual:astro:* from client optimizeDeps in core. Needed for prefetch users since virtual modules are now in the dependency graph.

  • #15764 44daecf Thanks @matthewp! - Fixes form actions incorrectly auto-executing during error page rendering. When an error page (e.g. 404) is rendered, form actions from the original request are no longer executed, since the full request handling pipeline is not active.

  • #15788 a91da9f Thanks @florian-lefebvre! - Reverts changes made to TSConfig templates

  • #15657 cb625b6 Thanks @qzio! - Adds a new security.actionBodySizeLimit option to configure the maximum size of Astro Actions request bodies.

    This lets you increase the default 1 MB limit when your actions need to accept larger payloads. For example, actions that handle file uploads or large JSON payloads can now opt in to a higher limit.

    If you do not set this option, Astro continues to enforce the 1 MB default to help prevent abuse.

    // astro.config.mjs
    export default defineConfig({
      security: {
        actionBodySizeLimit: 10 * 1024 * 1024, // set to 10 MB
      },
    });
  • #15176 9265546 Thanks @matthewp! - Fixes scripts in components not rendering when a sibling <Fragment slot="..."> exists but is unused

  • Updated dependencies [bbb5811, 4ebc1e3, cb99214, 80f0225, 727b0a2, 4e7f3e8, a164c77, 1fa4177, 7c55f80, cf6ea6b, 6f19ecc, f94d3c5, a18d727, 240c317, 745e632]:

    • @astrojs/markdown-remark@7.0.0
    • @astrojs/internal-helpers@0.8.0
withastro/starlight

Patch Changes

  • #3726 8a09b60 Thanks @delucis! - Fixes an issue using components containing scripts inside Starlight’s steps component in versions of Astro >= 5.16.9
withastro/astro

Minor Changes

  • #15778 4ebc1e3 Thanks @ematipico! - Added a new entry point called /request, which exposes utilities to work with the Request type:
    • getFirstForwardedValue: retrieves the first value of a multi-value header.
    • isValidIpAddress: checks whether a string contains only characters valid in IPv4/IPv6 addresses.
    • getValidatedIpFromHeader: extracts the first value from a header and validates it as an IP address.
    • getClientIpAddress: retrieves and validates the first IP from the x-forwarded-for header.

Patch Changes

  • #15700 4e7f3e8 Thanks @ocavue! - Adds a fork of createFilter from @rollup/pluginutils without Node.js APIs.
withastro/astro

Patch Changes

  • #15781 2de969d Thanks @ematipico! - Adds a new clientAddress option to the createContext() function

    Providing this value gives adapter and middleware authors explicit control over the client IP address. When not provided, accessing clientAddress throws an error consistent with other contexts where it is not set by the adapter.

    Additionally, both of the official Netlify and Vercel adapters have been updated to provide this information in their edge middleware.

    import { createContext } from 'astro/middleware';
    
    createContext({
      clientAddress: context.headers.get('x-real-ip'),
    });
  • #15778 4ebc1e3 Thanks @ematipico! - Fixes an issue where the computed clientAddress was incorrect in cases of a Request header with multiple values. The clientAddress is now also validated to contain only characters valid in IP addresses, rejecting injection payloads.

  • Updated dependencies [4ebc1e3, 4e7f3e8]:

    • @astrojs/internal-helpers@0.8.0-beta.3
withastro/astro

Patch Changes

  • #15781 2de969d Thanks @ematipico! - Adds a new clientAddress option to the createContext() function

    Providing this value gives adapter and middleware authors explicit control over the client IP address. When not provided, accessing clientAddress throws an error consistent with other contexts where it is not set by the adapter.

    Additionally, both of the official Netlify and Vercel adapters have been updated to provide this information in their edge middleware.

    import { createContext } from 'astro/middleware';
    
    createContext({
      clientAddress: context.headers.get('x-real-ip'),
    });
  • Updated dependencies [4ebc1e3, 4e7f3e8]:

    • @astrojs/internal-helpers@0.8.0-beta.3
    • @astrojs/underscore-redirects@1.0.0
withastro/astro

Minor Changes

  • #15759 39ff2a5 Thanks @matthewp! - Adds a new bodySizeLimit option to the @astrojs/node adapter

    You can now configure a maximum allowed request body size for your Node.js standalone server. The default limit is 1 GB. Set the value in bytes, or pass 0 to disable the limit entirely:

    import node from '@astrojs/node';
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      adapter: node({
        mode: 'standalone',
        bodySizeLimit: 1024 * 1024 * 100, // 100 MB
      }),
    });

Patch Changes

  • #15777 02e24d9 Thanks @matthewp! - Fixes CSRF origin check mismatch by passing the actual server listening port to createRequest, ensuring the constructed URL origin includes the correct port (e.g., http://localhost:4321 instead of http://localhost). Also restricts X-Forwarded-Proto to only be trusted when allowedDomains is configured.

  • #15763 1567e8c Thanks @matthewp! - Normalizes static file paths before evaluating dotfile access rules for improved consistency

  • Updated dependencies [4ebc1e3, 4e7f3e8]:

    • @astrojs/internal-helpers@0.8.0-beta.3
withastro/astro

Patch Changes

  • #15700 4e7f3e8 Thanks @ocavue! - Improves how React components are identified when setting the include and/or exclude options in projects where multiple JSX frameworks are used together

  • Updated dependencies [4ebc1e3, 4e7f3e8]:

    • @astrojs/internal-helpers@0.8.0-beta.3
withastro/astro

Patch Changes

  • #15700 4e7f3e8 Thanks @ocavue! - Improves how Preact components are identified when setting the include and/or exclude options in projects where multiple JSX frameworks are used together

  • Updated dependencies [4ebc1e3, 4e7f3e8]:

    • @astrojs/internal-helpers@0.8.0-beta.3
withastro/astro

Patch Changes

  • Updated dependencies [4ebc1e3, 4e7f3e8]:
    • @astrojs/internal-helpers@0.8.0-beta.3
    • @astrojs/markdown-remark@7.0.0-beta.11
withastro/astro

Patch Changes

  • Updated dependencies [4ebc1e3, 4e7f3e8]:
    • @astrojs/internal-helpers@0.8.0-beta.3
withastro/astro

Patch Changes

  • Updated dependencies []:
    • @astrojs/markdown-remark@7.0.0-beta.11
withastro/astro

Patch Changes

  • Updated dependencies [745e632]:
    • @astrojs/internal-helpers@0.8.0-beta.2
withastro/astro

Patch Changes

  • Updated dependencies [745e632]:
    • @astrojs/internal-helpers@0.8.0-beta.2
    • @astrojs/markdown-remark@7.0.0-beta.10
withastro/astro

Patch Changes

  • Updated dependencies [745e632]:
    • @astrojs/internal-helpers@0.8.0-beta.2
    • @astrojs/underscore-redirects@1.0.0
withastro/astro

Patch Changes

  • Updated dependencies []:
    • @astrojs/markdown-remark@7.0.0-beta.10
withastro/astro

Minor Changes

  • #15771 745e632 Thanks @rururux! - Adds the new utilities MANY_LEADING_SLASHES and collapseDuplicateLeadingSlashes.
withastro/astro

Patch Changes

  • Updated dependencies [745e632]:
    • @astrojs/internal-helpers@0.8.0-beta.2
withastro/astro

Patch Changes

  • Updated dependencies [745e632]:
    • @astrojs/internal-helpers@0.8.0-beta.2
withastro/astro

Patch Changes

  • Updated dependencies [6f19ecc, f94d3c5]:
    • @astrojs/markdown-remark@7.0.0-beta.9
withastro/astro

Major Changes

Patch Changes

withastro/astro

Patch Changes

  • Updated dependencies [6f19ecc, f94d3c5]:
    • @astrojs/markdown-remark@7.0.0-beta.9
withastro/astro

Minor Changes

  • #15495 5b99e90 Thanks @leekeh! - Adds new middlewareMode adapter feature and deprecates edgeMiddleware option

    The edgeMiddleware option is now deprecated and will be removed in a future release, so users should transition to using the new middlewareMode feature as soon as possible.

    export default defineConfig({
      adapter: vercel({
    -    edgeMiddleware: true
    +    middlewareMode: 'edge'
      })
    })
withastro/astro

Patch Changes

withastro/astro

Patch Changes

  • #15619 bbfa7c8 Thanks @rururux! - Fixed an issue where the Preact integration would incorrectly intercept React 19 components, triggering "Invalid hook call" error logs.
withastro/astro

Patch Changes

withastro/astro

Patch Changes

withastro/astro

Patch Changes

  • #15496 eb7cdda Thanks @matthewp! - Fix syntax highlighting for lowercase component tags that start with "style" or "script".
withastro/astro

Patch Changes

  • #15419 a18d727 Thanks @ematipico! - Fixes an issue where --add could accept any kind of string, leading to different errors. Now --add accepts only values of valid integrations and adapters.

  • #15419 a18d727 Thanks @ematipico! - Fixes an issue where the add command could accept any arbitrary value, leading the possible command injections. Now add and --add accepts
    values that are only acceptable npmjs.org names.

withastro/astro

Minor Changes

  • #15425 0317e99 Thanks @ocavue! - Updates @vitejs/plugin-vue to v6, @vitejs/plugin-vue-jsx to v5, and vite-plugin-vue-devtools to v8. No changes are needed from users.
withastro/astro

Minor Changes

  • #15077 a164c77 Thanks @matthewp! - Adds normalizePathname() utility function for normalizing URL pathnames to match the canonical form used by route generation.

  • #15419 a18d727 Thanks @ematipico! - Adds a new /cli specifier and the utility NPM_PACKAGE_NAME_REGEX.

withastro/astro

Patch Changes

  • #15383 876b664 Thanks @matthewp! - Fixes Preact components failing to render when using the Cloudflare adapter in dev mode.
withastro/astro

Patch Changes

withastro/astro

Patch Changes

  • #15344 9d87f77 Thanks @matthewp! - Fixes a hang that could occur when the npm registry is slow or unresponsive by adding a 10 second timeout to the version check

  • #15350 d758b68 Thanks @matthewp! - Errors when --add and --no-install flags are used together, as --add requires dependencies to be installed

withastro/astro

Patch Changes

withastro/astro

Patch Changes

withastro/starlight

Patch Changes


Last fetched:  |  Scheduled refresh: Every Saturday

See Customizing GitHub Activity Pages to configure your own

Inspired by releases.antfu.me